Subject: [PATCH] [FEAT SEC1800] zkey: Externalize secure key back-end functions
From: Philipp Rudo <prudo@linux.ibm.com>

Summary:     zkey: Add support of protected key crypto for dm-crypt.
Description: Support the usage of protected key crypto for dm-crypt disks in
             plain format by providing a tool to manage a key repository
             allowing to associate secure keys with disk partitions or logical
             volumes.
Upstream-ID: 5872f8a21ba222f9c32f0155ce1ac0f36c12cf39
Problem-ID:  SEC1800

Upstream-Description:

             zkey: Externalize secure key back-end functions

             To reduce the size of the zkey.c source file, all routines that
             deal with secure keys are moved to a new source file pkey.c.

             Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
             Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
             Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>


Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
---
 zkey/Makefile |    3 
 zkey/pkey.c   |  748 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 zkey/pkey.h   |   44 +++
 zkey/zkey.c   |  581 +++------------------------------------------
 4 files changed, 832 insertions(+), 544 deletions(-)

--- a/zkey/Makefile
+++ b/zkey/Makefile
@@ -25,9 +25,10 @@ all: check_dep zkey
 libs = $(rootdir)/libutil/libutil.a
 
 zkey.o: zkey.c pkey.h misc.h
+pkey.o: pkey.c pkey.h
 properties.o: properties.c properties.h
 
-zkey: zkey.o properties.o $(libs)
+zkey: zkey.o pkey.o properties.o $(libs)
 
 install: all
 	$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
--- /dev/null
+++ b/zkey/pkey.c
@@ -0,0 +1,748 @@
+/*
+ * zkey - Generate, re-encipher, and validate secure keys
+ *
+ * Copyright IBM Corp. 2018
+ *
+ * s390-tools is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "lib/util_base.h"
+#include "lib/util_libc.h"
+#include "lib/util_panic.h"
+
+#include "pkey.h"
+
+
+#define pr_verbose(verbose, fmt...)	do {				\
+						if (verbose)		\
+							warnx(fmt);	\
+					} while (0)
+
+#define DOUBLE_KEYSIZE_FOR_XTS(keysize, xts) ((xts) ? 2 * (keysize) : (keysize))
+#define HALF_KEYSIZE_FOR_XTS(keysize, xts)   ((xts) ? (keysize) / 2 : (keysize))
+
+/*
+ * Definitions for the CCA library
+ */
+#define CCA_LIBRARY_NAME	"libcsulcca.so"
+
+#define DEFAULT_KEYBITS 256
+
+/**
+ * Loads the CCA library and provides the entry point of the CSNBKTC function.
+ *
+ * @param[out] lib_csulcca   on return this contains the address of the CCA
+ *                           library. dlclose() should be used to free this
+ *                           when no longer needed.
+ * @param[out] dll_CSNBKTC   on return this contains the address of the
+ *                           CSNBKTC function.
+ * @param verbose            if true, verbose messages are printed
+ *
+ * @returns 0 on success, -ELIBACC in case of library load errors
+ */
+int load_cca_library(void **lib_csulcca, t_CSNBKTC *dll_CSNBKTC, bool verbose)
+{
+	util_assert(lib_csulcca != NULL, "Internal error: lib_csulcca is NULL");
+	util_assert(dll_CSNBKTC != NULL, "Internal error: dll_CSNBKTC is NULL");
+
+	/* Load the CCA library */
+	*lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW);
+	if (*lib_csulcca == NULL) {
+		warnx("%s\nEnsure that the IBM CCA Host Libraries and "
+		      "Tools are installed properly", dlerror());
+		return  -ELIBACC;
+	}
+
+	/* Get the Key Token Change function */
+	*dll_CSNBKTC = (t_CSNBKTC)dlsym(*lib_csulcca, "CSNBKTC");
+	if (*dll_CSNBKTC == NULL) {
+		warnx("%s\nEnsure that the IBM CCA Host Libraries and "
+		      "Tools are installed properly", dlerror());
+		dlclose(*lib_csulcca);
+		*lib_csulcca = NULL;
+		return -ELIBACC;
+	}
+
+	pr_verbose(verbose, "CCA library '%s' has been loaded successfully",
+		   CCA_LIBRARY_NAME);
+	return 0;
+}
+
+/**
+ * Opens the pkey device and returns its file descriptor.
+ *
+ * @param verbose            if true, verbose messages are printed
+ *
+ * @returns the file descriptor or -1 to indicate an error
+ */
+int open_pkey_device(bool verbose)
+{
+	int pkey_fd;
+
+	pkey_fd = open(PKEYDEVICE, O_RDWR);
+	if (pkey_fd < 0) {
+		warnx("File '%s:' %s\nEnsure that the 'pkey' kernel module "
+		      "is loaded", PKEYDEVICE, strerror(errno));
+		return -1;
+	}
+
+	pr_verbose(verbose, "Device '%s' has been opened successfully",
+		   PKEYDEVICE);
+	return pkey_fd;
+}
+
+/**
+ * Read a secure key file and return the allocated buffer and size.
+ *
+ * @param[in]  keyfile     the name of the file to read
+ * @param[out] secure_key_size  on return, the size of the secure key read
+ * @param[in]  verbose     if true, verbose messages are printed
+ *
+ * @return a buffer containing the secure key, or NULL in case of an error.
+ *         The returned buffer must be freed by the caller.
+ */
+u8 *read_secure_key(const char *keyfile, size_t *secure_key_size,
+		    bool verbose)
+{
+	size_t count, size;
+	struct stat sb;
+	char *msg;
+	FILE *fp;
+	u8 *buf;
+
+	util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
+	util_assert(secure_key_size != NULL,
+		    "Internal error: secure_key_size is NULL");
+
+	if (stat(keyfile, &sb)) {
+		warnx("File '%s': %s", keyfile, strerror(errno));
+		return NULL;
+	}
+	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);
+		return NULL;
+	}
+
+	fp = fopen(keyfile, "r");
+	if (fp == NULL) {
+		warnx("File '%s': %s", keyfile, strerror(errno));
+		return NULL;
+	}
+
+	buf = util_malloc(size);
+	count = fread(buf, 1, size, fp);
+	if (count <= 0) {
+		msg = feof(fp) ? "File is too small" : strerror(errno);
+		warnx("File '%s': %s", keyfile, msg);
+		free(buf);
+		buf = NULL;
+		goto out;
+	}
+
+	*secure_key_size = size;
+
+	if (verbose) {
+		pr_verbose(verbose, "%lu bytes read from file '%s'", size,
+			   keyfile);
+		util_hexdump_grp(stderr, NULL, buf, 4, size, 0);
+	}
+out:
+	fclose(fp);
+	return buf;
+}
+
+/**
+ * Write a secure key file
+ *
+ * @param[in] keyfile     the name of the file to write
+ * @param[in] secure_key  a buffer containing the secure key
+ * @param[in] secure_key_size the size of the secure key
+ * @param[in]  verbose     if true, verbose messages are printed
+ *
+ * @returns 0 in case of success, -EIO in case of an error
+ */
+int write_secure_key(const char *keyfile, const u8 *secure_key,
+		     size_t secure_key_size, bool verbose)
+{
+	size_t count;
+	FILE *fp;
+
+	util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
+	util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
+	util_assert(secure_key_size > 0,
+		    "Internal error: secure_key_size is zero");
+
+	fp = fopen(keyfile, "w");
+	if (fp == NULL) {
+		warnx("File '%s': %s", keyfile, strerror(errno));
+		return -EIO;
+	}
+
+	count = fwrite(secure_key, 1, secure_key_size, fp);
+	if (count <= 0) {
+		warnx("File '%s': %s", keyfile, strerror(errno));
+		fclose(fp);
+		return -EIO;
+	}
+
+	if (verbose) {
+		pr_verbose(verbose, "%lu bytes written to file '%s'",
+			   secure_key_size, keyfile);
+		util_hexdump_grp(stderr, NULL, secure_key, 4,
+				 secure_key_size, 0);
+	}
+	fclose(fp);
+	return 0;
+}
+
+/**
+ * Read a clear key file and return the allocated buffer and size
+ *
+ * @param[in]  keyfile     the name of the file to read
+ * @param[in]  keybits     the clear key size in bits. When keybits is 0, then
+ *                         the file size determines the keybits.
+ * @param[in]  xts         if true an XTS key is to be read
+ * @param[out] clear_key_size  on return, the size of the clear key read
+ * @param[in]  verbose     if true, verbose messages are printed
+ *
+ * @return a buffer containing the clear key, or NULL in case of an error.
+ *         The returned buffer must be freed by the caller.
+ */
+static u8 *read_clear_key(const char *keyfile, size_t keybits, bool xts,
+			  size_t *clear_key_size, bool verbose)
+{
+	size_t count, size, expected_size;
+	struct stat sb;
+	char *msg;
+	FILE *fp;
+	u8 *buf;
+
+	util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
+	util_assert(clear_key_size != NULL,
+		    "Internal error: clear_key_size is NULL");
+
+	if (stat(keyfile, &sb)) {
+		warnx("File '%s': %s", keyfile, strerror(errno));
+		return NULL;
+	}
+	size = sb.st_size;
+
+	if (keybits != 0) {
+		expected_size = DOUBLE_KEYSIZE_FOR_XTS(keybits / 8, xts);
+		if (size != expected_size) {
+			warnx("File '%s' has an invalid size, "
+			      "%lu bytes expected", keyfile, expected_size);
+			return NULL;
+		}
+	} else {
+		keybits = DOUBLE_KEYSIZE_FOR_XTS(size * 8, xts);
+	}
+
+	switch (keybits) {
+	case 128:
+		break;
+	case 192:
+		if (xts) {
+			warnx("File '%s' has an invalid size, "
+			      "192 bit keys are not supported with XTS",
+			      keyfile);
+			return NULL;
+		}
+		break;
+	case 256:
+		break;
+	default:
+		if (xts)
+			warnx("File '%s' has an invalid size, "
+			      "32 or 64 bytes expected", keyfile);
+		else
+			warnx("File '%s' has an invalid size, 16, 24 "
+			      "or 32 bytes expected", keyfile);
+		return NULL;
+	}
+
+	fp = fopen(keyfile, "r");
+	if (fp == NULL) {
+		warnx("File '%s': %s", keyfile, strerror(errno));
+		return NULL;
+	}
+
+	buf = util_malloc(size);
+	count = fread(buf, 1, size, fp);
+	if (count <= 0) {
+		msg = feof(fp) ? "File is too small" : strerror(errno);
+		warnx("File '%s': %s", keyfile, msg);
+		free(buf);
+		buf = NULL;
+		goto out;
+	}
+
+	*clear_key_size = size;
+
+	if (verbose) {
+		pr_verbose(verbose, "%lu bytes read from file '%s'", size,
+			   keyfile);
+		util_hexdump_grp(stderr, NULL, buf, 4, size, 0);
+	}
+out:
+	fclose(fp);
+	return buf;
+}
+
+/**
+ * Generate a secure key by random
+ *
+ * @param[in] pkey_fd       the pkey file descriptor
+ * @param[in] keyfile       the file name of the secure key to generate
+ * @param[in] keybits       the cryptographic size of the key in bits
+ * @param[in] xts           if true an XTS key is generated
+ * @param[in] card          the card number to use (or AUTOSELECT)
+ * @param[in] domain        the domain number to use (or AUTOSELECT)
+ * @param[in] verbose       if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error
+ */
+int generate_secure_key_random(int pkey_fd, const char *keyfile,
+			       size_t keybits, bool xts, u16 card, u16 domain,
+			       bool verbose)
+{
+	struct pkey_genseck gensec;
+	size_t secure_key_size;
+	u8 *secure_key;
+	int rc;
+
+	util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
+	util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
+
+	if (keybits == 0)
+		keybits = DEFAULT_KEYBITS;
+
+	secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts);
+	secure_key = util_malloc(secure_key_size);
+
+	pr_verbose(verbose, "Generate key on card %02x.%04x", card, domain);
+
+	gensec.cardnr = card;
+	gensec.domain = domain;
+	switch (keybits) {
+	case 128:
+		gensec.keytype = PKEY_KEYTYPE_AES_128;
+		break;
+	case 192:
+		if (xts) {
+			warnx("Invalid value for '--keybits'|'-c' "
+			      "for XTS: '%lu'", keybits);
+			rc = -EINVAL;
+			goto out;
+		}
+		gensec.keytype = PKEY_KEYTYPE_AES_192;
+		break;
+	case 256:
+		gensec.keytype = PKEY_KEYTYPE_AES_256;
+		break;
+	default:
+		warnx("Invalid value for '--keybits'/'-c': '%lu'", keybits);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec);
+	if (rc < 0) {
+		rc = -errno;
+		warnx("Failed to generate a secure key: %s", strerror(errno));
+		goto out;
+	}
+
+	memcpy(secure_key, &gensec.seckey, SECURE_KEY_SIZE);
+
+	if (xts) {
+		rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec);
+		if (rc < 0) {
+			rc = -errno;
+			warnx("Failed to generate a secure key: %s",
+			      strerror(errno));
+			goto out;
+		}
+
+		memcpy(secure_key + SECURE_KEY_SIZE, &gensec.seckey,
+		       SECURE_KEY_SIZE);
+	}
+
+	pr_verbose(verbose, "Successfully generated a secure key");
+
+	rc = write_secure_key(keyfile, secure_key, secure_key_size, verbose);
+
+out:
+	free(secure_key);
+	return rc;
+}
+
+
+/*
+ * Generate a secure key from a clear key file
+ *
+ * @param[in] pkey_fd       the pkey file descriptor
+ * @param[in] keyfile       the file name of the secure key to generate
+ * @param[in] keybits       the cryptographic size of the key in bits. When
+ *                          keybits is 0, then the clear key file size
+ *                          determines the keybits.
+ * @param[in] xts           if true an XTS key is generated
+ * @param[in] clearkeyfile  the file name of the clear key to read
+ * @param[in] card          the card number to use (or AUTOSELECT)
+ * @param[in] domain        the domain number to use (or AUTOSELECT)
+ * @param[in] verbose       if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error
+ */
+int generate_secure_key_clear(int pkey_fd, const char *keyfile,
+			      size_t keybits, bool xts,
+			      const char *clearkeyfile,
+			      u16 card, u16 domain,
+			      bool verbose)
+{
+	struct pkey_clr2seck clr2sec;
+	size_t secure_key_size;
+	size_t clear_key_size;
+	u8 *secure_key;
+	u8 *clear_key;
+	int rc;
+
+	util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
+	util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
+	util_assert(clearkeyfile != NULL,
+		    "Internal error: clearkeyfile is NULL");
+
+	secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts);
+	secure_key = util_malloc(secure_key_size);
+
+	clear_key = read_clear_key(clearkeyfile, keybits, xts, &clear_key_size,
+				   verbose);
+	if (clear_key == NULL)
+		return -EINVAL;
+
+	pr_verbose(verbose, "Generate key on card %02x.%04x", card, domain);
+
+	clr2sec.cardnr = card;
+	clr2sec.domain = domain;
+	switch (HALF_KEYSIZE_FOR_XTS(clear_key_size * 8, xts)) {
+	case 128:
+		clr2sec.keytype = PKEY_KEYTYPE_AES_128;
+		break;
+	case 192:
+		clr2sec.keytype = PKEY_KEYTYPE_AES_192;
+		break;
+	case 256:
+		clr2sec.keytype = PKEY_KEYTYPE_AES_256;
+		break;
+	default:
+		warnx("Invalid clear key size: '%lu' bytes", clear_key_size);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	memcpy(&clr2sec.clrkey, clear_key,
+	       HALF_KEYSIZE_FOR_XTS(clear_key_size, xts));
+
+	rc = ioctl(pkey_fd, PKEY_CLR2SECK, &clr2sec);
+	if (rc < 0) {
+		rc = -errno;
+		warnx("Failed to generate a secure key from a "
+		      "clear key: %s", strerror(errno));
+		goto out;
+	}
+
+	memcpy(secure_key, &clr2sec.seckey, SECURE_KEY_SIZE);
+
+	if (xts) {
+		memcpy(&clr2sec.clrkey, clear_key + clear_key_size / 2,
+		       clear_key_size / 2);
+
+		rc = ioctl(pkey_fd, PKEY_CLR2SECK, &clr2sec);
+		if (rc < 0) {
+			rc = -errno;
+			warnx("Failed to generate a secure key from "
+			      "a clear key: %s", strerror(errno));
+			goto out;
+		}
+
+		memcpy(secure_key+SECURE_KEY_SIZE, &clr2sec.seckey,
+		       SECURE_KEY_SIZE);
+	}
+
+	pr_verbose(verbose,
+		   "Successfully generated a secure key from a clear key");
+
+	rc = write_secure_key(keyfile, secure_key, secure_key_size, verbose);
+
+out:
+	memset(&clr2sec, 0, sizeof(clr2sec));
+	memset(clear_key, 0, clear_key_size);
+	free(clear_key);
+	free(secure_key);
+	return rc;
+}
+
+/**
+ * Prints CCA return and reason code information for certain known CCA
+ * error situations.
+ *
+ * @param return_code  the CCA return code
+ * @param reason_code  the CCA reason code
+ */
+static void print_CCA_error(int return_code, int reason_code)
+{
+	switch (return_code) {
+	case 8:
+		switch (reason_code) {
+		case 48:
+			warnx("The secure key has a CCA master key "
+			      "verification pattern that is not valid");
+			break;
+		}
+		break;
+	case 12:
+		switch (reason_code) {
+		case 764:
+			warnx("The CCA master key is not loaded and "
+			      "therefore a secure key cannot be enciphered");
+			break;
+		}
+		break;
+	}
+}
+
+/**
+ * Re-enciphers a secure key.
+ *
+ * @param[in] dll_CSNBKTC      the address of the CCA CSNBKTC function
+ * @param[in] secure_key       a buffer containing the secure key
+ * @param[in] secure_key_size  the size of the secure key
+ * @param[in] method           the re-enciphering method. METHOD_OLD_TO_CURRENT
+ *                             or METHOD_CURRENT_TO_NEW.
+ * @param[in] verbose          if true, verbose messages are printed
+ *
+ * @returns 0 on success, -EIO in case of an error
+ */
+int key_token_change(t_CSNBKTC dll_CSNBKTC,
+		     u8 *secure_key, unsigned int secure_key_size,
+		     char *method, bool verbose)
+{
+	long exit_data_len = 0, rule_array_count;
+	unsigned char rule_array[2 * 80] = { 0, };
+	unsigned char exit_data[4] = { 0, };
+	long return_code, reason_code;
+
+	util_assert(dll_CSNBKTC != NULL, "Internal error: dll_CSNBKTC is NULL");
+	util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
+	util_assert(secure_key_size > 0,
+		    "Internal error: secure_key_size is 0");
+	util_assert(method != NULL, "Internal error: method is NULL");
+
+	memcpy(rule_array, method, 8);
+	memcpy(rule_array + 8, "AES     ", 8);
+	rule_array_count = 2;
+
+	dll_CSNBKTC(&return_code, &reason_code,
+		      &exit_data_len, exit_data,
+		      &rule_array_count, rule_array,
+		      secure_key);
+
+	pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' returned: "
+		   "return_code: %ld, reason_code: %ld", method, return_code,
+		   reason_code);
+	if (return_code != 0) {
+		print_CCA_error(return_code, reason_code);
+		return -EIO;
+	}
+
+	if (secure_key_size == 2 * SECURE_KEY_SIZE) {
+		dll_CSNBKTC(&return_code, &reason_code,
+			      &exit_data_len, exit_data,
+			      &rule_array_count, rule_array,
+			      secure_key + SECURE_KEY_SIZE);
+
+		pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' "
+			   "returned: return_code: %ld, reason_code: %ld",
+			   method, return_code, reason_code);
+		if (return_code != 0) {
+			print_CCA_error(return_code, reason_code);
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+/**
+ * Validates an XTS secure key (the second part)
+ *
+ * @param[in] pkey_fd       the pkey file descriptor
+ * @param[in] secure_key    a buffer containing the secure key
+ * @param[in] secure_key_size the secure key size
+ * @param[in] part1_keysize the key size of the first key part
+ * @param[in] part1_attributes the attributes of the first key part
+ * @param[out] clear_key_bitsize on return , the cryptographic size of the
+ *                          clear key
+ * @param[in] verbose       if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error
+ */
+static int validate_secure_xts_key(int pkey_fd,
+				   u8 *secure_key, size_t secure_key_size,
+				   u16 part1_keysize, u32 part1_attributes,
+				   size_t *clear_key_bitsize, bool verbose)
+{
+	struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key;
+	struct pkey_verifykey verifykey;
+	struct secaeskeytoken *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);
+
+	if (secure_key_size != 2 * SECURE_KEY_SIZE) {
+		pr_verbose(verbose, "Size of secure key is too small: "
+			   "%lu expected %lu", secure_key_size,
+			   2 * SECURE_KEY_SIZE);
+		return -EINVAL;
+	}
+
+	if (token->bitsize != token2->bitsize) {
+		pr_verbose(verbose, "XTS secure key contains 2 clear keys of "
+			   "different sizes");
+		return -EINVAL;
+	}
+	if (token->keysize != token2->keysize) {
+		pr_verbose(verbose, "XTS secure key contains 2 keys of "
+			   "different sizes");
+		return -EINVAL;
+	}
+	if (memcmp(&token->mkvp, &token2->mkvp, sizeof(token->mkvp)) != 0) {
+		pr_verbose(verbose, "XTS secure key contains 2 keys using "
+			   "different CCA master keys");
+		return -EINVAL;
+	}
+
+	memcpy(&verifykey.seckey, token2, sizeof(verifykey.seckey));
+
+	rc = ioctl(pkey_fd, PKEY_VERIFYKEY, &verifykey);
+	if (rc < 0) {
+		rc = -errno;
+		pr_verbose(verbose, "Failed to validate a secure key: %s",
+			   strerror(-rc));
+		return rc;
+	}
+
+	if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) {
+		pr_verbose(verbose, "Secure key is not an AES key");
+		return -EINVAL;
+	}
+
+	if (verifykey.keysize != part1_keysize) {
+		pr_verbose(verbose, "XTS secure key contains 2 keys using "
+			   "different key sizes");
+		return -EINVAL;
+	}
+
+	if (verifykey.attributes != part1_attributes) {
+		pr_verbose(verbose, "XTS secure key contains 2 keys using "
+			   "different attributes");
+		return -EINVAL;
+	}
+
+	if (clear_key_bitsize)
+		*clear_key_bitsize += verifykey.keysize;
+
+	return 0;
+}
+
+/**
+ * Validates a secure key
+ *
+ * @param[in] pkey_fd       the pkey file descriptor
+ * @param[in] secure_key    a buffer containing the secure key
+ * @param[in] secure_key_size the secure key size
+ * @param[out] clear_key_bitsize on return , the cryptographic size of the
+ *                          clear key
+ * @param[out] is_old_mk    in return set to 1 to indicate if the secure key
+ *                          is currently enciphered by the OLD CCA master key
+ * @param[in] verbose       if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error
+ */
+int validate_secure_key(int pkey_fd,
+			u8 *secure_key, size_t secure_key_size,
+			size_t *clear_key_bitsize, int *is_old_mk,
+			bool verbose)
+{
+	struct secaeskeytoken *token = (struct secaeskeytoken *)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) {
+		pr_verbose(verbose, "Size of secure key is too small: "
+			   "%lu expected %lu", secure_key_size,
+			   SECURE_KEY_SIZE);
+		return -EINVAL;
+	}
+
+	memcpy(&verifykey.seckey, token, sizeof(verifykey.seckey));
+
+	rc = ioctl(pkey_fd, PKEY_VERIFYKEY, &verifykey);
+	if (rc < 0) {
+		rc = -errno;
+		pr_verbose(verbose, "Failed to validate a secure key: %s",
+			   strerror(-rc));
+		return rc;
+	}
+
+	if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) {
+		pr_verbose(verbose, "Secure key is not an AES key");
+		return -EINVAL;
+	}
+
+	if (clear_key_bitsize)
+		*clear_key_bitsize = verifykey.keysize;
+
+	/* XTS uses 2 secure key tokens concatenated to each other */
+	if (secure_key_size > SECURE_KEY_SIZE) {
+		rc = validate_secure_xts_key(pkey_fd,
+					     secure_key, secure_key_size,
+					     verifykey.keysize,
+					     verifykey.attributes,
+					     clear_key_bitsize,
+					     verbose);
+		if (rc != 0)
+			return rc;
+	}
+
+	if (is_old_mk)
+		*is_old_mk = (verifykey.attributes &
+			      PKEY_VERIFY_ATTR_OLD_MKVP) != 0;
+
+	pr_verbose(verbose, "Secure key validation completed successfully");
+
+	return 0;
+}
--- a/zkey/pkey.h
+++ b/zkey/pkey.h
@@ -4,7 +4,7 @@
  * This header file defines the interface to the pkey kernel module.
  * It defines a set of IOCTL commands with its associated structures.
  *
- * Copyright 2017 IBM Corp.
+ * Copyright IBM Corp. 2017, 2018
  *
  * s390-tools is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
@@ -82,4 +82,44 @@ struct pkey_verifykey {
 
 #define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey)
 
-#endif
\ No newline at end of file
+#define METHOD_OLD_TO_CURRENT	"RTCMK   "
+#define METHOD_CURRENT_TO_NEW	"RTNMK   "
+
+typedef void (*t_CSNBKTC)(long *return_code,
+			  long *reason_code,
+			  long *exit_data_length,
+			  unsigned char *exit_data,
+			  long *rule_array_count,
+			  unsigned char *rule_array,
+			  unsigned char *key_identifier);
+
+int load_cca_library(void **lib_csulcca, t_CSNBKTC *dll_CSNBKTC, bool verbose);
+
+int open_pkey_device(bool verbose);
+
+int generate_secure_key_random(int pkey_fd, const char *keyfile,
+			       size_t keybits, bool xts, u16 card, u16 domain,
+			       bool verbose);
+
+int generate_secure_key_clear(int pkey_fd, const char *keyfile,
+			      size_t keybits, bool xts,
+			      const char *clearkeyfile,
+			      u16 card, u16 domain,
+			      bool verbose);
+
+u8 *read_secure_key(const char *keyfile, size_t *secure_key_size,
+		    bool verbose);
+
+int write_secure_key(const char *keyfile, const u8 *secure_key,
+		     size_t secure_key_size, bool verbose);
+
+int validate_secure_key(int pkey_fd,
+			u8 *secure_key, size_t secure_key_size,
+			size_t *clear_key_bitsize, int *is_old_mk,
+			bool verbose);
+
+int key_token_change(t_CSNBKTC dll_CSNBKTC,
+		     u8 *secure_key, unsigned int secure_key_size,
+		     char *method, bool verbose);
+
+#endif
--- a/zkey/zkey.c
+++ b/zkey/zkey.c
@@ -188,9 +188,6 @@ static struct zkey_command zkey_commands
 #define pr_verbose(fmt...)	if (g.verbose) \
 					warnx(fmt)
 
-#define DOUBLE_KEYSIZE_FOR_XTS(keysize, xts) (xts) ? 2 * (keysize) : (keysize)
-#define HALF_KEYSIZE_FOR_XTS(keysize, xts) (xts) ? (keysize) / 2 : (keysize)
-
 static void print_usage_command(const struct zkey_command *command)
 {
 	char command_str[ZKEY_COMMAND_STR_LEN];
@@ -253,19 +250,6 @@ static void print_help(const struct zkey
 }
 
 /*
- * Definitions for the CCA library
- */
-#define CCA_LIBRARY_NAME	"libcsulcca.so"
-
-typedef void (*t_CSNBKTC)(long *return_code,
-			  long *reason_code,
-			  long *exit_data_length,
-			  unsigned char *exit_data,
-			  long *rule_array_count,
-			  unsigned char *rule_array,
-			  unsigned char *key_identifier);
-
-/*
  * Global variables for program options
  */
 static struct zkey_globals {
@@ -283,212 +267,6 @@ static struct zkey_globals {
 	.pkey_fd = -1,
 };
 
-#define DEFAULT_KEYBITS 256
-
-static int load_cca_library(void)
-{
-	/* Load the CCA library */
-	g.lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW);
-	if (g.lib_csulcca == NULL) {
-		warnx("%s\nEnsure that the IBM CCA Host Libraries and "
-		      "Tools are installed properly", dlerror());
-		return  EXIT_FAILURE;
-	}
-
-	/* Get the Key Token Change function */
-	g.dll_CSNBKTC = (t_CSNBKTC)dlsym(g.lib_csulcca, "CSNBKTC");
-	if (g.dll_CSNBKTC == NULL) {
-		warnx("%s\nEnsure that the IBM CCA Host Libraries and "
-		      "Tools are installed properly", dlerror());
-		dlclose(g.lib_csulcca);
-		g.lib_csulcca = NULL;
-		return EXIT_FAILURE;
-	}
-
-	pr_verbose("CCA library '%s' has been loaded successfully",
-		   CCA_LIBRARY_NAME);
-
-	return EXIT_SUCCESS;
-}
-
-static int open_pkey_device(void)
-{
-	g.pkey_fd = open(PKEYDEVICE, O_RDWR);
-	if (g.pkey_fd < 0) {
-		warnx("File '%s:' %s\nEnsure that the 'pkey' kernel module "
-		      "is loaded", PKEYDEVICE, strerror(errno));
-		return EXIT_FAILURE;
-	}
-
-	pr_verbose("Device '%s' has been opened successfully", PKEYDEVICE);
-
-	return EXIT_SUCCESS;
-}
-
-/*
- * Read a secure key file and return the allocated buffer and size
- */
-static u8 *read_secure_key(const char *keyfile, size_t *secure_key_size)
-{
-	size_t count, size;
-	struct stat sb;
-	char *msg;
-	FILE *fp;
-	u8 *buf;
-
-	if (stat(keyfile, &sb)) {
-		warnx("File '%s': %s", keyfile, strerror(errno));
-		return NULL;
-	}
-	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);
-		return NULL;
-	}
-
-	fp = fopen(keyfile, "r");
-	if (fp == NULL) {
-		warnx("File '%s': %s", keyfile, strerror(errno));
-		return NULL;
-	}
-
-	buf = util_malloc(size);
-	count = fread(buf, 1, size, fp);
-	if (count <= 0) {
-		msg = feof(fp) ? "File is too small" : strerror(errno);
-		warnx("File '%s': %s", keyfile, msg);
-		free(buf);
-		buf = NULL;
-		goto out;
-	}
-
-	*secure_key_size = size;
-
-	if (g.verbose) {
-		pr_verbose("%lu bytes read from file '%s'", size, keyfile);
-		util_hexdump_grp(stderr, NULL, buf, 4, size, 0);
-	}
-out:
-	fclose(fp);
-	return buf;
-}
-
-/*
- * Write a secure key file
- */
-static int write_secure_key(const char *keyfile, const u8 *secure_key,
-			    size_t secure_key_size)
-{
-	size_t count;
-	FILE *fp;
-
-	fp = fopen(keyfile, "w");
-	if (fp == NULL) {
-		warnx("File '%s': %s", keyfile, strerror(errno));
-		return EXIT_FAILURE;
-	}
-
-	count = fwrite(secure_key, 1, secure_key_size, fp);
-	if (count <= 0) {
-		warnx("File '%s': %s", keyfile, strerror(errno));
-		fclose(fp);
-		return EXIT_FAILURE;
-	}
-
-	if (g.verbose) {
-		pr_verbose("%lu bytes written to file '%s'",
-			   secure_key_size, keyfile);
-		util_hexdump_grp(stderr, NULL, secure_key, 4,
-				 secure_key_size, 0);
-	}
-	fclose(fp);
-	return EXIT_SUCCESS;
-}
-
-/*
- * Read a clear key file and return the allocated buffer and size
- *
- * When keybits is 0, then the file size determines the keybits.
- */
-static u8 *read_clear_key(const char *keyfile, size_t keybits,
-			  size_t *clear_key_size)
-{
-	size_t count, size, expected_size;
-	struct stat sb;
-	char *msg;
-	FILE *fp;
-	u8 *buf;
-
-	if (stat(keyfile, &sb)) {
-		warnx("File '%s': %s", keyfile, strerror(errno));
-		return NULL;
-	}
-	size = sb.st_size;
-
-	if (keybits != 0) {
-		expected_size = DOUBLE_KEYSIZE_FOR_XTS(keybits / 8, g.xts);
-		if (size != expected_size) {
-			warnx("File '%s' has an invalid size, "
-			      "%lu bytes expected", keyfile, expected_size);
-			return NULL;
-		}
-	} else {
-		keybits = DOUBLE_KEYSIZE_FOR_XTS(size * 8, g.xts);
-	}
-
-	switch (keybits) {
-	case 128:
-		break;
-	case 192:
-		if (g.xts) {
-			warnx("File '%s' has an invalid size, "
-			      "192 bit keys are not supported with XTS",
-			      keyfile);
-			return NULL;
-		}
-		break;
-	case 256:
-		break;
-	default:
-		if (g.xts)
-			warnx("File '%s' has an invalid size, "
-			      "32 or 64 bytes expected", keyfile);
-		else
-			warnx("File '%s' has an invalid size, 16, 24 "
-			      "or 32 bytes expected", keyfile);
-		return NULL;
-	}
-
-	fp = fopen(keyfile, "r");
-	if (fp == NULL) {
-		warnx("File '%s': %s", keyfile, strerror(errno));
-		return NULL;
-	}
-
-	buf = util_malloc(size);
-	count = fread(buf, 1, size ,fp);
-	if (count <= 0) {
-		msg = feof(fp) ? "File is too small" : strerror(errno);
-		warnx("File '%s': %s", keyfile, msg);
-		free(buf);
-		buf = NULL;
-		goto out;
-	}
-
-	*clear_key_size = size;
-
-	if (g.verbose) {
-		pr_verbose("%lu bytes read from file '%s'", size, keyfile);
-		util_hexdump_grp(stderr, NULL, buf, 4, size, 0);
-	}
-out:
-	fclose(fp);
-	return buf;
-}
-
 /*
  * Command handler for 'generate with clear key'
  *
@@ -496,76 +274,15 @@ out:
  */
 static int command_generate_clear(const char *keyfile)
 {
-	struct pkey_clr2seck clr2sec;
-	size_t secure_key_size;
-	size_t clear_key_size;
-	u8 *secure_key;
-	u8 *clear_key;
 	int rc;
 
-	secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, g.xts);
-	secure_key = util_malloc(secure_key_size);
-
-	clear_key = read_clear_key(g.clearkeyfile, g.keybits, &clear_key_size);
-	if (clear_key == NULL)
-		return EXIT_FAILURE;
-
-	clr2sec.cardnr = AUTOSELECT;
-	clr2sec.domain = AUTOSELECT;
-	switch (HALF_KEYSIZE_FOR_XTS(clear_key_size * 8, g.xts)) {
-	case 128:
-		clr2sec.keytype = PKEY_KEYTYPE_AES_128;
-		break;
-	case 192:
-		clr2sec.keytype = PKEY_KEYTYPE_AES_192;
-		break;
-	case 256:
-		clr2sec.keytype = PKEY_KEYTYPE_AES_256;
-		break;
-	default:
-		warnx("Invalid clear key size: '%lu' bytes", clear_key_size);
-		rc = EXIT_FAILURE;
-		goto out;
-	}
-
-	memcpy(&clr2sec.clrkey, clear_key,
-	       HALF_KEYSIZE_FOR_XTS(clear_key_size, g.xts));
-
-	rc = ioctl(g.pkey_fd, PKEY_CLR2SECK, &clr2sec);
-	if (rc < 0) {
-		warnx("Failed to generate a secure key from a "
-		      "clear key: %s", strerror(errno));
+	rc = generate_secure_key_clear(g.pkey_fd, keyfile,
+				       g.keybits, g.xts,
+				       g.clearkeyfile,
+				       AUTOSELECT, AUTOSELECT,
+				       g.verbose);
+	if (rc != 0)
 		rc = EXIT_FAILURE;
-		goto out;
-	}
-
-	memcpy(secure_key, &clr2sec.seckey, SECURE_KEY_SIZE);
-
-	if (g.xts) {
-		memcpy(&clr2sec.clrkey, clear_key + clear_key_size / 2,
-		       clear_key_size / 2);
-
-		rc = ioctl(g.pkey_fd, PKEY_CLR2SECK, &clr2sec);
-		if (rc < 0) {
-			warnx("Failed to generate a secure key from "
-			      "a clear key: %s", strerror(errno));
-			rc = EXIT_FAILURE;
-			goto out;
-		}
-
-		memcpy(secure_key+SECURE_KEY_SIZE, &clr2sec.seckey,
-		       SECURE_KEY_SIZE);
-	}
-
-	pr_verbose("Successfully generated a secure key from a clear key");
-
-	rc = write_secure_key(keyfile, secure_key, secure_key_size);
-
-out:
-	memset(&clr2sec, 0, sizeof(clr2sec));
-	memset(clear_key, 0, clear_key_size);
-	free(clear_key);
-	free(secure_key);
 	return rc;
 }
 
@@ -576,69 +293,15 @@ out:
  */
 static int command_generate_random(const char *keyfile)
 {
-	struct pkey_genseck gensec;
-	size_t secure_key_size;
-	u8 *secure_key;
 	int rc;
 
-	if (g.keybits == 0)
-		g.keybits = DEFAULT_KEYBITS;
-
-	secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, g.xts);
-	secure_key = util_malloc(secure_key_size);
-
-	gensec.cardnr = AUTOSELECT;
-	gensec.domain = AUTOSELECT;
-	switch (g.keybits) {
-	case 128:
-		gensec.keytype = PKEY_KEYTYPE_AES_128;
-		break;
-	case 192:
-		if (g.xts) {
-			warnx("Invalid value for '--keybits'|'-c' "
-			      "for XTS: '%lu'", g.keybits);
-			rc = EXIT_FAILURE;
-			goto out;
-		}
-		gensec.keytype = PKEY_KEYTYPE_AES_192;
-		break;
-	case 256:
-		gensec.keytype = PKEY_KEYTYPE_AES_256;
-		break;
-	default:
-		warnx("Invalid value for '--keybits'/'-c': '%lu'", g.keybits);
+	rc = generate_secure_key_random(g.pkey_fd, keyfile,
+					g.keybits, g.xts,
+					AUTOSELECT, AUTOSELECT,
+					g.verbose);
+	if (rc != 0)
 		rc = EXIT_FAILURE;
-		goto out;
-	}
-
-	rc = ioctl(g.pkey_fd, PKEY_GENSECK, &gensec);
-	if (rc < 0) {
-		warnx("Failed to generate a secure key: %s", strerror(errno));
-		rc = EXIT_FAILURE;
-		goto out;
-	}
-
-	memcpy(secure_key, &gensec.seckey, SECURE_KEY_SIZE);
-
-	if (g.xts) {
-		rc = ioctl(g.pkey_fd, PKEY_GENSECK, &gensec);
-		if (rc < 0) {
-			warnx("Failed to generate a secure key: %s",
-			      strerror(errno));
-			rc = EXIT_FAILURE;
-			goto out;
-		}
-
-		memcpy(secure_key + SECURE_KEY_SIZE, &gensec.seckey,
-		       SECURE_KEY_SIZE);
-	}
-
-	pr_verbose("Successfully generated a secure key");
 
-	rc = write_secure_key(keyfile, secure_key, secure_key_size);
-
-out:
-	free(secure_key);
 	return rc;
 }
 
@@ -653,182 +316,6 @@ static int command_generate(const char *
 			      : command_generate_random(keyfile);
 }
 
-static void print_CCA_error(int return_code, int reason_code)
-{
-	switch (return_code) {
-	case 8:
-		switch (reason_code) {
-		case 48:
-			warnx("The secure key has a CCA master key "
-			      "verification pattern that is not valid");
-			break;
-		}
-		break;
-	case 12:
-		switch (reason_code) {
-		case 764:
-			warnx("The CCA master key is not loaded and "
-			      "therefore a secure key cannot be enciphered");
-			break;
-		}
-		break;
-	}
-}
-
-static int key_token_change(u8 *secure_key, unsigned int secure_key_size,
-			    char *method)
-{
-	long exit_data_len = 0, rule_array_count;
-	unsigned char rule_array[2 * 80] = { 0, };
-	unsigned char exit_data[4] = { 0, };
-	long return_code, reason_code;
-
-	memcpy(rule_array, method, 8);
-	memcpy(rule_array + 8, "AES     ", 8);
-	rule_array_count = 2;
-
-	g.dll_CSNBKTC(&return_code, &reason_code,
-		      &exit_data_len, exit_data,
-		      &rule_array_count, rule_array,
-		      secure_key);
-
-	pr_verbose("CSNBKTC (Key Token Change) with '%s' returned: "
-		   "return_code: %ld, reason_code: %ld",
-		   method, return_code, reason_code);
-	if (return_code != 0) {
-		print_CCA_error(return_code, reason_code);
-		return EXIT_FAILURE;
-	}
-
-	if (secure_key_size == 2 * SECURE_KEY_SIZE) {
-		g.dll_CSNBKTC(&return_code, &reason_code,
-			      &exit_data_len, exit_data,
-			      &rule_array_count, rule_array,
-			      secure_key + SECURE_KEY_SIZE);
-
-		pr_verbose("CSNBKTC (Key Token Change) with '%s' "
-			   "returned: return_code: %ld, reason_code: %ld",
-			   method, return_code, reason_code);
-		if (return_code != 0) {
-			print_CCA_error(return_code, reason_code);
-			return EXIT_FAILURE;
-		}
-	}
-	return EXIT_SUCCESS;
-}
-
-static int validate_secure_xts_key(u8 *secure_key, size_t secure_key_size,
-				   u16 part1_keysize, u32 part1_attributes,
-				   size_t *clear_key_bitsize)
-{
-	struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key;
-	struct pkey_verifykey verifykey;
-	struct secaeskeytoken *token2;
-	int rc;
-
-	/* XTS uses 2 secure key tokens concatenated to each other */
-	token2 = (struct secaeskeytoken *)(secure_key + SECURE_KEY_SIZE);
-
-	if (secure_key_size != 2 * SECURE_KEY_SIZE) {
-		pr_verbose("Size of secure key is too small: %lu expected %lu",
-			   secure_key_size, 2 * SECURE_KEY_SIZE);
-		return EXIT_FAILURE;
-	}
-
-	if (token->bitsize != token2->bitsize) {
-		pr_verbose("XTS secure key contains 2 clear keys of "
-			   "different sizes");
-		return EXIT_FAILURE;
-	}
-	if (token->keysize != token2->keysize) {
-		pr_verbose("XTS secure key contains 2 keys of different "
-			   "sizes");
-		return EXIT_FAILURE;
-	}
-	if (memcmp(&token->mkvp, &token2->mkvp, sizeof(token->mkvp)) != 0) {
-		pr_verbose("XTS secure key contains 2 keys using different "
-			   "CCA master keys");
-		return EXIT_FAILURE;
-	}
-
-	memcpy(&verifykey.seckey, token2, sizeof(verifykey.seckey));
-
-	rc = ioctl(g.pkey_fd, PKEY_VERIFYKEY, &verifykey);
-	if (rc < 0) {
-		warnx("Failed to validate a secure key: %s", strerror(errno));
-		return EXIT_FAILURE;
-	}
-
-	if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) {
-		pr_verbose("Secure key is not an AES key");
-		return EXIT_FAILURE;
-	}
-
-	if (verifykey.keysize != part1_keysize) {
-		pr_verbose("XTS secure key contains 2 keys using different "
-			   "key sizes");
-		return EXIT_FAILURE;
-	}
-
-	if (verifykey.attributes != part1_attributes) {
-		pr_verbose("XTS secure key contains 2 keys using different "
-			   "attributes");
-		return EXIT_FAILURE;
-	}
-
-	if (clear_key_bitsize)
-		*clear_key_bitsize += verifykey.keysize;
-
-	return EXIT_SUCCESS;
-}
-
-static int validate_secure_key(u8 *secure_key, size_t secure_key_size,
-			       size_t *clear_key_bitsize, int *is_old_mk)
-{
-	struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key;
-	struct pkey_verifykey verifykey;
-	int rc;
-
-	if (secure_key_size < SECURE_KEY_SIZE) {
-		pr_verbose("Size of secure key is too small: %lu expected %lu",
-			   secure_key_size, SECURE_KEY_SIZE);
-		return EXIT_FAILURE;
-	}
-
-	memcpy(&verifykey.seckey, token, sizeof(verifykey.seckey));
-
-	rc = ioctl(g.pkey_fd, PKEY_VERIFYKEY, &verifykey);
-	if (rc < 0) {
-		warnx("Failed to validate a secure key: %s", strerror(errno));
-		return EXIT_FAILURE;
-	}
-
-	if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) {
-		pr_verbose("Secure key is not an AES key");
-		return EXIT_FAILURE;
-	}
-
-	if (clear_key_bitsize)
-		*clear_key_bitsize = verifykey.keysize;
-
-	/* XTS uses 2 secure key tokens concatenated to each other */
-	if (secure_key_size > SECURE_KEY_SIZE) {
-		rc = validate_secure_xts_key(secure_key, secure_key_size,
-					     verifykey.keysize,
-					     verifykey.attributes,
-					     clear_key_bitsize);
-		if (rc != EXIT_SUCCESS)
-			return rc;
-	}
-
-	if (is_old_mk)
-		*is_old_mk = (verifykey.attributes &
-			      PKEY_VERIFY_ATTR_OLD_MKVP) != 0;
-
-	pr_verbose("Secure key validation completed successfully");
-
-	return EXIT_SUCCESS;
-}
 
 /*
  * Command handler for 'reencipher'.
@@ -842,14 +329,15 @@ static int command_reencipher(const char
 	u8 *secure_key;
 
 	/* Read the secure key to be re-enciphered */
-	secure_key = read_secure_key(keyfile, &secure_key_size);
+	secure_key = read_secure_key(keyfile, &secure_key_size, g.verbose);
 	if (secure_key == NULL)
 		return EXIT_FAILURE;
 
-	rc = validate_secure_key(secure_key, secure_key_size, NULL,
-				 &is_old_mk);
-	if (rc != EXIT_SUCCESS) {
+	rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, NULL,
+				 &is_old_mk, g.verbose);
+	if (rc != 0) {
 		warnx("The secure key in file '%s' is not valid", keyfile);
+		rc = EXIT_FAILURE;
 		goto out;
 	}
 
@@ -884,10 +372,14 @@ static int command_reencipher(const char
 		pr_verbose("Secure key will be re-enciphered from OLD to the "
 			   "CURRENT CCA master key");
 
-		rc = key_token_change(secure_key, secure_key_size, "RTCMK   ");
-		if (rc != EXIT_SUCCESS) {
+		rc = key_token_change(g.dll_CSNBKTC,
+				      secure_key, secure_key_size,
+				      METHOD_OLD_TO_CURRENT,
+				      g.verbose);
+		if (rc != 0) {
 			warnx("Re-encipher from OLD to CURRENT CCA "
 			      "master key has failed");
+			rc = EXIT_FAILURE;
 			goto out;
 		}
 	}
@@ -895,10 +387,13 @@ static int command_reencipher(const char
 		pr_verbose("Secure key will be re-enciphered from CURRENT "
 			   "to the NEW CCA master key");
 
-		rc = key_token_change(secure_key, secure_key_size, "RTNMK   ");
-		if (rc != EXIT_SUCCESS) {
+		rc = key_token_change(g.dll_CSNBKTC,
+				      secure_key, secure_key_size,
+				      METHOD_CURRENT_TO_NEW, g.verbose);
+		if (rc != 0) {
 			warnx("Re-encipher from CURRENT to NEW CCA "
 			      "master key has failed");
+			rc = EXIT_FAILURE;
 			goto out;
 		}
 	}
@@ -907,7 +402,9 @@ static int command_reencipher(const char
 
 	/* Write the migrated secure key */
 	rc = write_secure_key(g.outputfile ? g.outputfile : keyfile,
-			      secure_key, secure_key_size);
+			      secure_key, secure_key_size, g.verbose);
+	if (rc != 0)
+		rc = EXIT_FAILURE;
 out:
 	free(secure_key);
 	return rc;
@@ -927,14 +424,15 @@ static int command_validate(const char *
 	int rc;
 
 	/* Read the secure key to be re-enciphered */
-	secure_key = read_secure_key(keyfile, &secure_key_size);
+	secure_key = read_secure_key(keyfile, &secure_key_size, g.verbose);
 	if (secure_key == NULL)
 		return EXIT_FAILURE;
 
-	rc = validate_secure_key(secure_key, secure_key_size, &clear_key_size,
-				 &is_old_mk);
-	if (rc != EXIT_SUCCESS) {
+	rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size,
+				 &clear_key_size, &is_old_mk, g.verbose);
+	if (rc != 0) {
 		warnx("The secure key in file '%s' is not valid", keyfile);
+		rc = EXIT_FAILURE;
 		goto out;
 	}
 
@@ -1083,13 +581,14 @@ int main(int argc, char *argv[])
 	}
 
 	if (command->need_cca_library) {
-		rc = load_cca_library();
-		if (rc != EXIT_SUCCESS)
+		rc = load_cca_library(&g.lib_csulcca, &g.dll_CSNBKTC,
+				      g.verbose);
+		if (rc != 0)
 			goto out;
 	}
 	if (command->need_pkey_device) {
-		rc = open_pkey_device();
-		if (rc != EXIT_SUCCESS)
+		g.pkey_fd = open_pkey_device(g.verbose);
+		if (g.pkey_fd == -1)
 			goto out;
 	}
 
