diff --git a/zkey/cca.c b/zkey/cca.c index 2669c751..9ad1558d 100644 --- a/zkey/cca.c +++ b/zkey/cca.c @@ -215,11 +215,11 @@ int key_token_change(struct cca_lib *cca, return -EIO; } - if (secure_key_size == 2 * SECURE_KEY_SIZE) { + if (secure_key_size == 2 * AESDATA_KEY_SIZE) { cca->dll_CSNBKTC(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, - secure_key + SECURE_KEY_SIZE); + secure_key + AESDATA_KEY_SIZE); pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' " "returned: return_code: %ld, reason_code: %ld", diff --git a/zkey/keystore.c b/zkey/keystore.c index b42f2ae2..2344bb15 100644 --- a/zkey/keystore.c +++ b/zkey/keystore.c @@ -70,8 +70,6 @@ struct key_filenames { #define DEFAULT_VOLUME_TYPE VOLUME_TYPE_PLAIN #endif -#define IS_XTS(secure_key_size) (secure_key_size > SECURE_KEY_SIZE ? 1 : 0) - #define REC_KEY "Key" #define REC_DESCRIPTION "Description" #define REC_SEC_KEY_SIZE "Secure key size" @@ -1440,7 +1438,7 @@ static int _keystore_generate_verification_pattern(struct keystore *keystore, if (key == NULL) return -EIO; - rc = generate_key_verification_pattern((const char *)key, key_size, + rc = generate_key_verification_pattern(key, key_size, vp, vp_len, keystore->verbose); free(key); @@ -1854,6 +1852,7 @@ int keystore_import_key(struct keystore *keystore, const char *name, struct key_filenames file_names = { NULL, NULL, NULL }; struct properties *key_props = NULL; size_t secure_key_size; + const char *key_type; u8 *secure_key; u64 mkvp; int rc; @@ -1877,6 +1876,14 @@ int keystore_import_key(struct keystore *keystore, const char *name, goto out_free_key_filenames; } + key_type = get_key_type(secure_key, secure_key_size); + if (key_type == NULL) { + warnx("Key '%s' is not a valid secure key", name); + free(secure_key); + rc = -EINVAL; + goto out_free_key_filenames; + } + rc = get_master_key_verification_pattern(secure_key, secure_key_size, &mkvp, keystore->verbose); if (rc != 0) { @@ -1907,7 +1914,7 @@ int keystore_import_key(struct keystore *keystore, const char *name, rc = _keystore_create_info_file(keystore, name, &file_names, description, volumes, apqns, noapqncheck, sector_size, volume_type, - KEY_TYPE_CCA_AESDATA); + key_type); if (rc != 0) goto out_free_props; @@ -2252,7 +2259,7 @@ static void _keystore_print_record(struct util_rec *rec, const char *name, struct properties *properties, bool validation, const char *skey_filename, - size_t secure_key_size, + size_t secure_key_size, bool is_xts, size_t clear_key_bitsize, bool valid, bool is_old_mk, bool reenc_pending, u64 mkvp) { @@ -2308,13 +2315,12 @@ static void _keystore_print_record(struct util_rec *rec, util_rec_set(rec, REC_DESCRIPTION, description != NULL ? description : ""); util_rec_set(rec, REC_SEC_KEY_SIZE, "%lu bytes", secure_key_size); - if (!validation || valid) + if ((!validation || valid) && clear_key_bitsize != 0) util_rec_set(rec, REC_CLR_KEY_SIZE, "%lu bits", clear_key_bitsize); else util_rec_set(rec, REC_CLR_KEY_SIZE, "(unknown)"); - util_rec_set(rec, REC_XTS, - IS_XTS(secure_key_size) ? "Yes" : "No"); + util_rec_set(rec, REC_XTS, is_xts ? "Yes" : "No"); util_rec_set(rec, REC_KEY_TYPE, key_type); if (validation) { if (valid) @@ -2525,6 +2531,7 @@ static int _keystore_process_validate(struct keystore *keystore, _keystore_print_record(info->rec, name, properties, 1, file_names->skey_filename, secure_key_size, + is_xts_key(secure_key, secure_key_size), clear_key_bitsize, valid, is_old_mk, _keystore_reencipher_key_exists(file_names), mkvp); @@ -3297,29 +3304,29 @@ static int _keystore_display_key(struct keystore *keystore, void *private) { struct util_rec *rec = (struct util_rec *)private; - struct secaeskeytoken *secure_key; - size_t secure_key_size; + u8 *secure_key; + size_t secure_key_size, clear_key_bitsize = 0; int rc = 0; - secure_key = (struct secaeskeytoken *) - read_secure_key(file_names->skey_filename, + secure_key = read_secure_key(file_names->skey_filename, &secure_key_size, keystore->verbose); if (secure_key == NULL) return -EIO; - if (secure_key_size < SECURE_KEY_SIZE) { + if (secure_key_size < MIN_SECURE_KEY_SIZE) { pr_verbose(keystore, "Size of secure key is too small: %lu expected %lu", - secure_key_size, SECURE_KEY_SIZE); + secure_key_size, MIN_SECURE_KEY_SIZE); rc = -EIO; goto out; } + get_key_bit_size(secure_key, secure_key_size, &clear_key_bitsize); + _keystore_print_record(rec, name, properties, 0, file_names->skey_filename, secure_key_size, - IS_XTS(secure_key_size) ? secure_key->bitsize * 2 - : secure_key->bitsize, - 0, 0, + is_xts_key(secure_key, secure_key_size), + clear_key_bitsize, 0, 0, _keystore_reencipher_key_exists(file_names), 0); out: @@ -3681,37 +3688,6 @@ out: return cipher_spec; } -/** - * Returns the size of the secure key file - * - * @param[in] keystore the keystore - * @param[in] skey_filename the file name of the secure key - * - * @returns the size of the secure key, or -1 in case of an error - */ -static size_t _keystore_get_key_file_size(struct keystore *keystore, - const char *skey_filename) -{ - size_t secure_key_size; - struct stat sb; - - if (stat(skey_filename, &sb)) { - pr_verbose(keystore, "Key file '%s': %s", - skey_filename, strerror(errno)); - return -1; - } - - secure_key_size = sb.st_size; - if (secure_key_size < SECURE_KEY_SIZE) { - pr_verbose(keystore, - "Size of secure key is too small: %lu expected %lu", - secure_key_size, SECURE_KEY_SIZE); - return -1; - } - - return secure_key_size; -} - /** * Processing function for the cryptsetup and crypttab functions. * Extracts the required information and calls the secondary processing function @@ -3738,6 +3714,7 @@ static int _keystore_process_crypt(struct keystore *keystore, size_t secure_key_size; size_t sector_size = 0; char *volumes = NULL; + u8 *secure_key = NULL; char *dmname; char *temp; int rc = 0; @@ -3745,18 +3722,14 @@ static int _keystore_process_crypt(struct keystore *keystore, char *ch; int i; - secure_key_size = _keystore_get_key_file_size(keystore, - file_names->skey_filename); - if (secure_key_size < SECURE_KEY_SIZE) { - pr_verbose(keystore, - "Size of secure key is too small: %lu expected %lu", - secure_key_size, SECURE_KEY_SIZE); - rc = -EIO; - goto out; - } + secure_key = read_secure_key(file_names->skey_filename, + &secure_key_size, keystore->verbose); + if (secure_key == NULL) + return -EIO; cipher_spec = _keystore_build_cipher_spec(properties, - IS_XTS(secure_key_size)); + is_xts_key(secure_key, + secure_key_size)); if (cipher_spec == NULL) { rc = -EINVAL; goto out; @@ -3808,6 +3781,8 @@ out: free(cipher_spec); if (volume_type != NULL) free(volume_type); + if (secure_key != NULL) + free(secure_key); return rc; } diff --git a/zkey/pkey.c b/zkey/pkey.c index 24720250..914013a4 100644 --- a/zkey/pkey.c +++ b/zkey/pkey.c @@ -98,10 +98,8 @@ u8 *read_secure_key(const char *keyfile, size_t *secure_key_size, } size = sb.st_size; - if (size != SECURE_KEY_SIZE && size != 2*SECURE_KEY_SIZE) { - warnx("File '%s' has an invalid size, %lu or %lu bytes " - "expected", keyfile, SECURE_KEY_SIZE, - 2 * SECURE_KEY_SIZE); + if (size < MIN_SECURE_KEY_SIZE || size > 2 * MAX_SECURE_KEY_SIZE) { + warnx("File '%s' has an invalid size: %lu", keyfile, size); return NULL; } @@ -306,7 +304,7 @@ int generate_secure_key_random(int pkey_fd, const char *keyfile, if (keybits == 0) keybits = DEFAULT_KEYBITS; - secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts); + secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(AESDATA_KEY_SIZE, xts); secure_key = util_malloc(secure_key_size); pr_verbose(verbose, "Generate key on card %02x.%04x", card, domain); @@ -344,7 +342,7 @@ int generate_secure_key_random(int pkey_fd, const char *keyfile, goto out; } - memcpy(secure_key, &gensec.seckey, SECURE_KEY_SIZE); + memcpy(secure_key, &gensec.seckey, AESDATA_KEY_SIZE); if (xts) { rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec); @@ -357,8 +355,8 @@ int generate_secure_key_random(int pkey_fd, const char *keyfile, goto out; } - memcpy(secure_key + SECURE_KEY_SIZE, &gensec.seckey, - SECURE_KEY_SIZE); + memcpy(secure_key + AESDATA_KEY_SIZE, &gensec.seckey, + AESDATA_KEY_SIZE); } pr_verbose(verbose, "Successfully generated a secure key"); @@ -412,7 +410,7 @@ int generate_secure_key_clear(int pkey_fd, const char *keyfile, return -EINVAL; } - secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts); + secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(AESDATA_KEY_SIZE, xts); secure_key = util_malloc(secure_key_size); clear_key = read_clear_key(clearkeyfile, keybits, xts, &clear_key_size, @@ -453,7 +451,7 @@ int generate_secure_key_clear(int pkey_fd, const char *keyfile, goto out; } - memcpy(secure_key, &clr2sec.seckey, SECURE_KEY_SIZE); + memcpy(secure_key, &clr2sec.seckey, AESDATA_KEY_SIZE); if (xts) { memcpy(&clr2sec.clrkey, clear_key + clear_key_size / 2, @@ -469,8 +467,8 @@ int generate_secure_key_clear(int pkey_fd, const char *keyfile, goto out; } - memcpy(secure_key+SECURE_KEY_SIZE, &clr2sec.seckey, - SECURE_KEY_SIZE); + memcpy(secure_key + AESDATA_KEY_SIZE, &clr2sec.seckey, + AESDATA_KEY_SIZE); } pr_verbose(verbose, @@ -505,21 +503,21 @@ static int validate_secure_xts_key(int pkey_fd, u16 part1_keysize, u32 part1_attributes, size_t *clear_key_bitsize, bool verbose) { - struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key; + struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key; struct pkey_verifykey verifykey; - struct secaeskeytoken *token2; + struct aesdatakeytoken *token2; int rc; util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1"); util_assert(secure_key != NULL, "Internal error: secure_key is NULL"); /* XTS uses 2 secure key tokens concatenated to each other */ - token2 = (struct secaeskeytoken *)(secure_key + SECURE_KEY_SIZE); + token2 = (struct aesdatakeytoken *)(secure_key + AESDATA_KEY_SIZE); - if (secure_key_size != 2 * SECURE_KEY_SIZE) { + if (secure_key_size != 2 * AESDATA_KEY_SIZE) { pr_verbose(verbose, "Size of secure key is too small: " "%lu expected %lu", secure_key_size, - 2 * SECURE_KEY_SIZE); + 2 * AESDATA_KEY_SIZE); return -EINVAL; } @@ -591,17 +589,17 @@ int validate_secure_key(int pkey_fd, size_t *clear_key_bitsize, int *is_old_mk, bool verbose) { - struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key; + struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key; struct pkey_verifykey verifykey; int rc; util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1"); util_assert(secure_key != NULL, "Internal error: secure_key is NULL"); - if (secure_key_size < SECURE_KEY_SIZE) { + if (secure_key_size < AESDATA_KEY_SIZE) { pr_verbose(verbose, "Size of secure key is too small: " "%lu expected %lu", secure_key_size, - SECURE_KEY_SIZE); + AESDATA_KEY_SIZE); return -EINVAL; } @@ -624,7 +622,7 @@ int validate_secure_key(int pkey_fd, *clear_key_bitsize = verifykey.keysize; /* XTS uses 2 secure key tokens concatenated to each other */ - if (secure_key_size > SECURE_KEY_SIZE) { + if (secure_key_size > AESDATA_KEY_SIZE) { rc = validate_secure_xts_key(pkey_fd, secure_key, secure_key_size, verifykey.keysize, @@ -656,7 +654,7 @@ int validate_secure_key(int pkey_fd, * * @returns 0 on success, a negative errno in case of an error */ -int generate_key_verification_pattern(const char *key, size_t key_size, +int generate_key_verification_pattern(const u8 *key, size_t key_size, char *vp, size_t vp_len, bool verbose) { int tfmfd = -1, opfd = -1, rc = 0; @@ -691,7 +689,7 @@ int generate_key_verification_pattern(const char *key, size_t key_size, } snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(paes)", - key_size > SECURE_KEY_SIZE ? "xts" : "cbc"); + is_xts_key(key, key_size) ? "xts" : "cbc"); tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0); if (tfmfd < 0) { @@ -788,15 +786,15 @@ int get_master_key_verification_pattern(const u8 *secure_key, size_t secure_key_size, u64 *mkvp, bool verbose) { - struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key; + struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key; util_assert(secure_key != NULL, "Internal error: secure_key is NULL"); util_assert(mkvp != NULL, "Internal error: mkvp is NULL"); - if (secure_key_size < SECURE_KEY_SIZE) { + if (secure_key_size < AESDATA_KEY_SIZE) { pr_verbose(verbose, "Size of secure key is too small: " "%lu expected %lu", secure_key_size, - SECURE_KEY_SIZE); + AESDATA_KEY_SIZE); return -EINVAL; } @@ -817,7 +815,7 @@ bool is_cca_aes_data_key(const u8 *key, size_t key_size) { struct tokenheader *hdr = (struct tokenheader *)key; - if (key == NULL || key_size < SECURE_KEY_SIZE) + if (key == NULL || key_size < AESDATA_KEY_SIZE) return false; if (hdr->type != TOKEN_TYPE_CCA_INTERNAL) @@ -828,6 +826,57 @@ bool is_cca_aes_data_key(const u8 *key, size_t key_size) return true; } +/** + * Check if the specified key is an XTS type key + * + * @param[in] key the secure key token + * @param[in] key_size the size of the secure key + * + * @returns true if the key is an XTS key type + */ +bool is_xts_key(const u8 *key, size_t key_size) +{ + if (is_cca_aes_data_key(key, key_size)) { + if (key_size == 2 * AESDATA_KEY_SIZE && + is_cca_aes_data_key(key + AESDATA_KEY_SIZE, + key_size - AESDATA_KEY_SIZE)) + return true; + } + + return false; +} + +/** + * Gets the size in bits of the effective key of the specified secure key + * + * @param[in] key the secure key token + * @param[in] key_size the size of the secure key + * @param[out] bitsize On return, contains the size in bits of the key. + * If the key size can not be determined, then 0 is + * passed back as bitsize. + * + * @returns 0 on success, a negative errno in case of an error + */ +int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize) +{ + struct aesdatakeytoken *datakey = (struct aesdatakeytoken *)key; + + util_assert(bitsize != NULL, "Internal error: bitsize is NULL"); + + if (is_cca_aes_data_key(key, key_size)) { + *bitsize = datakey->bitsize; + if (key_size == 2 * AESDATA_KEY_SIZE) { + datakey = (struct aesdatakeytoken *)key + + AESDATA_KEY_SIZE; + *bitsize += datakey->bitsize; + } + } else { + return -EINVAL; + } + + return 0; +} + /** * Returns the type of the key * diff --git a/zkey/pkey.h b/zkey/pkey.h index 22ead8c1..e5a103a7 100644 --- a/zkey/pkey.h +++ b/zkey/pkey.h @@ -30,10 +30,10 @@ struct tokenheader { #define TOKEN_VERSION_AESDATA 0x04 -struct secaeskeytoken { - u8 type; /* 0x01 for internal key token */ +struct aesdatakeytoken { + u8 type; /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */ u8 res0[3]; - u8 version; /* should be 0x04 */ + u8 version; /* should be TOKEN_VERSION_AESDATA (0x04) */ u8 res1[1]; u8 flag; /* key flags */ u8 res2[1]; @@ -45,10 +45,13 @@ struct secaeskeytoken { u8 tvv[4]; /* token validation value */ } __packed; -#define SECURE_KEY_SIZE sizeof(struct secaeskeytoken) +#define AESDATA_KEY_SIZE sizeof(struct aesdatakeytoken) + +#define MAX_SECURE_KEY_SIZE AESDATA_KEY_SIZE +#define MIN_SECURE_KEY_SIZE AESDATA_KEY_SIZE struct pkey_seckey { - u8 seckey[SECURE_KEY_SIZE]; /* the secure key blob */ + u8 seckey[AESDATA_KEY_SIZE]; /* the secure key blob */ }; struct pkey_clrkey { @@ -123,7 +126,7 @@ int validate_secure_key(int pkey_fd, size_t *clear_key_bitsize, int *is_old_mk, bool verbose); -int generate_key_verification_pattern(const char *key, size_t key_size, +int generate_key_verification_pattern(const u8 *key, size_t key_size, char *vp, size_t vp_len, bool verbose); int get_master_key_verification_pattern(const u8 *secure_key, @@ -131,6 +134,8 @@ int get_master_key_verification_pattern(const u8 *secure_key, bool verbose); bool is_cca_aes_data_key(const u8 *key, size_t key_size); +bool is_xts_key(const u8 *key, size_t key_size); +int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize); const char *get_key_type(const u8 *key, size_t key_size); #endif diff --git a/zkey/zkey-cryptsetup.c b/zkey/zkey-cryptsetup.c index 293b8efd..055af18f 100644 --- a/zkey/zkey-cryptsetup.c +++ b/zkey/zkey-cryptsetup.c @@ -1329,22 +1329,25 @@ static int activate_unbound_keyslot(int token, int keyslot, const char *key, return rc; } -static int check_keysize_and_cipher_mode(size_t keysize) +static int check_keysize_and_cipher_mode(const u8 *key, size_t keysize) { - if (keysize == 0) { + if (keysize < MIN_SECURE_KEY_SIZE || + keysize > 2 * MAX_SECURE_KEY_SIZE) { warnx("Invalid volume key size"); return -EINVAL; } if (strncmp(crypt_get_cipher_mode(g.cd), "xts", 3) == 0) { - if (keysize != 2 * SECURE_KEY_SIZE) { + if (keysize < 2 * MIN_SECURE_KEY_SIZE || + (key != NULL && !is_xts_key(key, keysize))) { warnx("The volume key size %lu is not valid for the " "cipher mode '%s'", keysize, crypt_get_cipher_mode(g.cd)); return -EINVAL; } } else { - if (keysize != SECURE_KEY_SIZE) { + if (keysize > MAX_SECURE_KEY_SIZE || + (key != NULL && is_xts_key(key, keysize))) { warnx("The volume key size %lu is not valid for the " "cipher mode '%s'", keysize, crypt_get_cipher_mode(g.cd)); @@ -1377,7 +1380,7 @@ static int open_keyslot(int keyslot, char **key, size_t *keysize, vkeysize = crypt_get_volume_key_size(g.cd); pr_verbose("Volume key size: %lu", vkeysize); - rc = check_keysize_and_cipher_mode(vkeysize); + rc = check_keysize_and_cipher_mode(NULL, vkeysize); if (rc != 0) return rc; @@ -1571,7 +1574,7 @@ static int reencipher_prepare(int token) if (rc != 0) goto out; - rc = generate_key_verification_pattern(key, keysize, + rc = generate_key_verification_pattern((u8 *)key, keysize, reenc_tok.verification_pattern, sizeof(reenc_tok.verification_pattern), g.verbose); @@ -1851,8 +1854,8 @@ static int reencipher_complete(int token) } - rc = generate_key_verification_pattern(key, keysize, vp, sizeof(vp), - g.verbose); + rc = generate_key_verification_pattern((u8 *)key, keysize, vp, + sizeof(vp), g.verbose); if (rc != 0) { warnx("Failed to generate the verification pattern: %s", strerror(-rc)); @@ -1998,7 +2001,7 @@ static int command_validate(void) printf(" Status: %s\n", is_valid ? "Valid" : "Invalid"); printf(" Secure key size: %lu bytes\n", keysize); printf(" XTS type key: %s\n", - keysize > SECURE_KEY_SIZE ? "Yes" : "No"); + is_xts_key((u8 *)key, keysize) ? "Yes" : "No"); printf(" Key type: %s\n", get_key_type((u8 *)key, keysize)); if (is_valid) { @@ -2076,7 +2079,7 @@ static int command_setvp(void) token = find_token(g.cd, PAES_VP_TOKEN_NAME); - rc = generate_key_verification_pattern(key, keysize, + rc = generate_key_verification_pattern((const u8 *)key, keysize, vp_tok.verification_pattern, sizeof(vp_tok.verification_pattern), g.verbose); @@ -2131,7 +2134,7 @@ static int command_setkey(void) if (newkey == NULL) return EXIT_FAILURE; - rc = check_keysize_and_cipher_mode(newkey_size); + rc = check_keysize_and_cipher_mode(newkey, newkey_size); if (rc != 0) goto out; @@ -2180,7 +2183,7 @@ static int command_setkey(void) goto out; } - rc = generate_key_verification_pattern((char *)newkey, newkey_size, vp, + rc = generate_key_verification_pattern(newkey, newkey_size, vp, sizeof(vp), g.verbose); if (rc != 0) { warnx("Failed to generate the verification pattern: %s", diff --git a/zkey/zkey.c b/zkey/zkey.c index 44e65cb8..39902f09 100644 --- a/zkey/zkey.c +++ b/zkey/zkey.c @@ -1413,7 +1413,7 @@ static int command_validate_file(void) goto out; } - rc = generate_key_verification_pattern((char *)secure_key, + rc = generate_key_verification_pattern(secure_key, secure_key_size, vp, sizeof(vp), g.verbose); if (rc != 0) { @@ -1441,7 +1441,7 @@ static int command_validate_file(void) get_key_type(secure_key, secure_key_size)); printf(" Clear key size: %lu bits\n", clear_key_size); printf(" XTS type key: %s\n", - secure_key_size > SECURE_KEY_SIZE ? "Yes" : "No"); + is_xts_key(secure_key, secure_key_size) ? "Yes" : "No"); printf(" Enciphered with: %s CCA master key (MKVP: %016llx)\n", is_old_mk ? "OLD" : "CURRENT", mkvp); printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2,