/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "lib/util_base.h" #include "lib/util_libc.h" #include "lib/util_panic.h" #include "pkey.h" #ifndef AF_ALG #define AF_ALG 38 #endif #ifndef SOL_ALG #define SOL_ALG 279 #endif #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)) #define MAX_CIPHER_LEN 32 /* * Definitions for the CCA library */ #define CCA_LIBRARY_NAME "libcsulcca.so" #define CCA_WEB_PAGE "http://www.ibm.com/security/cryptocards" #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) { pr_verbose(verbose, "%s", dlerror()); warnx("The command requires the IBM CCA Host Libraries and " "Tools.\nFor the supported environments and downloads, " "see:\n%s", CCA_WEB_PAGE); return -ELIBACC; } /* Get the Key Token Change function */ *dll_CSNBKTC = (t_CSNBKTC)dlsym(*lib_csulcca, "CSNBKTC"); if (*dll_CSNBKTC == NULL) { pr_verbose(verbose, "%s", dlerror()); warnx("The command requires the IBM CCA Host Libraries and " "Tools.\nFor the supported environments and downloads, " "see:\n%s", CCA_WEB_PAGE); 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 != size) { msg = ferror(fp) ? strerror(errno) : "File is too small"; 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 != secure_key_size) { 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 != size) { msg = ferror(fp) ? strerror(errno) : "File is too small"; 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)); warnx("Make sure that all available CCA crypto adapters are " "setup with the same master key"); 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)); warnx("Make sure that all available CCA crypto " "adapters are setup with the same master key"); 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)); warnx("Make sure that all available CCA crypto adapters are " "setup with the same master key"); 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)); warnx("Make sure that all available CCA crypto " "adapters are setup with the same master key"); 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; } /** * Generate a key verification pattern of a secure key by encrypting the all * zero message with the secure key using the AF_ALG interface * * @param[in] key the secure key token * @param[in] key_size the size of the secure key * @param[in] vp buffer where the verification pattern is returned * @param[in] vp_len the size of the buffer * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of an error */ int generate_key_verification_pattern(const char *key, size_t key_size, char *vp, size_t vp_len, bool verbose) { int tfmfd = -1, opfd = -1, rc = 0; char null_msg[ENC_ZERO_LEN]; char enc_zero[ENC_ZERO_LEN]; struct af_alg_iv *alg_iv; struct cmsghdr *header; uint32_t *type; ssize_t len; size_t i; struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "skcipher", }; struct iovec iov = { .iov_base = (void *)null_msg, .iov_len = sizeof(null_msg), }; int iv_msg_size = CMSG_SPACE(sizeof(*alg_iv) + PAES_BLOCK_SIZE); char buffer[CMSG_SPACE(sizeof(*type)) + iv_msg_size]; struct msghdr msg = { .msg_control = buffer, .msg_controllen = sizeof(buffer), .msg_iov = &iov, .msg_iovlen = 1, }; if (vp_len < VERIFICATION_PATTERN_LEN) { rc = -EMSGSIZE; goto out; } snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(paes)", key_size > SECURE_KEY_SIZE ? "xts" : "cbc"); tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0); if (tfmfd < 0) { rc = -errno; pr_verbose(verbose, "Failed to open an AF_ALG socket"); goto out; } if (bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { rc = -errno; pr_verbose(verbose, "Failed to bind the AF_ALG socket, " "salg_name='%s' ", sa.salg_name); goto out; } if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, key_size) < 0) { rc = -errno; pr_verbose(verbose, "Failed to set the key"); goto out; } opfd = accept(tfmfd, NULL, 0); if (opfd < 0) { rc = -errno; pr_verbose(verbose, "Failed to accept on the AF_ALG socket"); goto out; } memset(null_msg, 0, sizeof(null_msg)); memset(buffer, 0, sizeof(buffer)); header = CMSG_FIRSTHDR(&msg); if (header == NULL) { pr_verbose(verbose, "Failed to obtain control message header"); rc = -EINVAL; goto out; } header->cmsg_level = SOL_ALG; header->cmsg_type = ALG_SET_OP; header->cmsg_len = CMSG_LEN(sizeof(*type)); type = (void *)CMSG_DATA(header); *type = ALG_OP_ENCRYPT; header = CMSG_NXTHDR(&msg, header); if (header == NULL) { pr_verbose(verbose, "Failed to obtain control message " "header"); rc = -EINVAL; goto out; } header->cmsg_level = SOL_ALG; header->cmsg_type = ALG_SET_IV; header->cmsg_len = iv_msg_size; alg_iv = (void *)CMSG_DATA(header); alg_iv->ivlen = PAES_BLOCK_SIZE; memcpy(alg_iv->iv, null_msg, PAES_BLOCK_SIZE); len = sendmsg(opfd, &msg, 0); if (len != ENC_ZERO_LEN) { pr_verbose(verbose, "Failed to send to the AF_ALG socket"); rc = -errno; goto out; } len = read(opfd, enc_zero, sizeof(enc_zero)); if (len != ENC_ZERO_LEN) { pr_verbose(verbose, "Failed to receive from the AF_ALG socket"); rc = -errno; goto out; } memset(vp, 0, vp_len); for (i = 0; i < sizeof(enc_zero); i++) sprintf(&vp[i * 2], "%02x", enc_zero[i]); pr_verbose(verbose, "Key verification pattern: %s", vp); out: if (opfd != -1) close(opfd); if (tfmfd != -1) close(tfmfd); if (rc != 0) pr_verbose(verbose, "Failed to generate the key verification " "pattern: %s", strerror(-rc)); return rc; }