/* * COPYRIGHT (c) International Business Machines Corp. 2001-2017 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /* * openCryptoki CCA token * * Author: Kent E. Yoder * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "cca_stdll.h" #include "pkcs11types.h" #include "p11util.h" #include "defs.h" #include "host_defs.h" #include "tok_specific.h" #include "tok_struct.h" #include "h_extern.h" #include "csulincl.h" #include "ec_defs.h" #include "trace.h" #include "ock_syslog.h" #include "cca_func.h" #include /** * EC definitions */ /** * the point is encoded as z||x, where the octet z specifies * which solution of the quadratic equation y is */ #define POINT_CONVERSION_COMPRESSED 0x02 /** * the point is encoded as z||x||y, where z is the octet 0x04 */ #define POINT_CONVERSION_UNCOMPRESSED 0x04 /** * the point is encoded as z||x||y, where the octet z specifies * which solution of the quadratic equation y is */ #define POINT_CONVERSION_HYBRID 0x06 const char manuf[] = "IBM"; const char model[] = "CCA"; const char descr[] = "IBM CCA Token"; const char label[] = "ccatok"; #define CCASHAREDLIB "libcsulcca.so" static CSNBCKI_t dll_CSNBCKI; static CSNBCKM_t dll_CSNBCKM; static CSNBDKX_t dll_CSNBDKX; static CSNBDKM_t dll_CSNBDKM; static CSNBMKP_t dll_CSNBMKP; static CSNBKEX_t dll_CSNBKEX; static CSNBKGN_t dll_CSNBKGN; static CSNBKGN2_t dll_CSNBKGN2; static CSNBKIM_t dll_CSNBKIM; static CSNBKPI_t dll_CSNBKPI; static CSNBKPI2_t dll_CSNBKPI2; static CSNBKSI_t dll_CSNBKSI; static CSNBKRC_t dll_CSNBKRC; static CSNBAKRC_t dll_CSNBAKRC; static CSNBKRD_t dll_CSNBKRD; static CSNBKRL_t dll_CSNBKRL; static CSNBKRR_t dll_CSNBKRR; static CSNBKRW_t dll_CSNBKRW; static CSNDKRC_t dll_CSNDKRC; static CSNDKRD_t dll_CSNDKRD; static CSNDKRL_t dll_CSNDKRL; static CSNDKRR_t dll_CSNDKRR; static CSNDKRW_t dll_CSNDKRW; static CSNBKYT_t dll_CSNBKYT; static CSNBKYTX_t dll_CSNBKYTX; static CSNBKTC_t dll_CSNBKTC; static CSNBKTR_t dll_CSNBKTR; static CSNBRNG_t dll_CSNBRNG; static CSNBRNGL_t dll_CSNBRNGL; static CSNBSAE_t dll_CSNBSAE; static CSNBSAD_t dll_CSNBSAD; static CSNBDEC_t dll_CSNBDEC; static CSNBENC_t dll_CSNBENC; static CSNBMGN_t dll_CSNBMGN; static CSNBMVR_t dll_CSNBMVR; static CSNBKTB_t dll_CSNBKTB; static CSNBKTB2_t dll_CSNBKTB2; static CSNDPKG_t dll_CSNDPKG; static CSNDPKB_t dll_CSNDPKB; static CSNBOWH_t dll_CSNBOWH; static CSNDPKI_t dll_CSNDPKI; static CSNDDSG_t dll_CSNDDSG; static CSNDDSV_t dll_CSNDDSV; static CSNDKTC_t dll_CSNDKTC; static CSNDPKX_t dll_CSNDPKX; static CSNDSYI_t dll_CSNDSYI; static CSNDSYX_t dll_CSNDSYX; static CSUACFQ_t dll_CSUACFQ; static CSUACFC_t dll_CSUACFC; static CSNDSBC_t dll_CSNDSBC; static CSNDSBD_t dll_CSNDSBD; static CSUALCT_t dll_CSUALCT; static CSUAACM_t dll_CSUAACM; static CSUAACI_t dll_CSUAACI; static CSNDPKH_t dll_CSNDPKH; static CSNDPKR_t dll_CSNDPKR; static CSUAMKD_t dll_CSUAMKD; static CSNDRKD_t dll_CSNDRKD; static CSNDRKL_t dll_CSNDRKL; static CSNDSYG_t dll_CSNDSYG; static CSNBPTR_t dll_CSNBPTR; static CSNBCPE_t dll_CSNBCPE; static CSNBCPA_t dll_CSNBCPA; static CSNBPGN_t dll_CSNBPGN; static CSNBPVR_t dll_CSNBPVR; static CSNBDKG_t dll_CSNBDKG; static CSNBEPG_t dll_CSNBEPG; static CSNBCVE_t dll_CSNBCVE; static CSNBCSG_t dll_CSNBCSG; static CSNBCSV_t dll_CSNBCSV; static CSNBCVG_t dll_CSNBCVG; static CSNBKTP_t dll_CSNBKTP; static CSNDPKE_t dll_CSNDPKE; static CSNDPKD_t dll_CSNDPKD; static CSNBPEX_t dll_CSNBPEX; static CSNBPEXX_t dll_CSNBPEXX; static CSUARNT_t dll_CSUARNT; static CSNBCVT_t dll_CSNBCVT; static CSNBMDG_t dll_CSNBMDG; static CSUACRA_t dll_CSUACRA; static CSUACRD_t dll_CSUACRD; static CSNBTRV_t dll_CSNBTRV; static CSNBSKY_t dll_CSNBSKY; static CSNBSPN_t dll_CSNBSPN; static CSNBPCU_t dll_CSNBPCU; static CSUAPCV_t dll_CSUAPCV; static CSUAPRB_t dll_CSUAPRB; static CSUADHK_t dll_CSUADHK; static CSUADHQ_t dll_CSUADHQ; static CSNDTBC_t dll_CSNDTBC; static CSNDRKX_t dll_CSNDRKX; static CSNBKET_t dll_CSNBKET; static CSNBHMG_t dll_CSNBHMG; static CSNBHMV_t dll_CSNBHMV; static CSNBCTT2_t dll_CSNBCTT2; /* mechanisms provided by this token */ static const MECH_LIST_ELEMENT cca_mech_list[] = { {CKM_DES_KEY_GEN, {8, 8, CKF_HW | CKF_GENERATE}}, {CKM_DES3_KEY_GEN, {24, 24, CKF_HW | CKF_GENERATE}}, {CKM_RSA_PKCS_KEY_PAIR_GEN, {512, 4096, CKF_HW | CKF_GENERATE_KEY_PAIR}}, {CKM_RSA_PKCS, {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY | CKF_WRAP | CKF_UNWRAP}}, {CKM_MD5_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA1_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA224_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA256_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA1_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA224_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA256_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {CKM_RSA_PKCS_OAEP, {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}}, {CKM_DES_CBC, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {CKM_DES_CBC_PAD, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {CKM_DES3_CBC, {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {CKM_DES3_CBC_PAD, {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, #ifndef NOAES {CKM_AES_KEY_GEN, {16, 32, CKF_HW | CKF_GENERATE}}, {CKM_AES_ECB, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {CKM_AES_CBC, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {CKM_AES_CBC_PAD, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, #endif {CKM_SHA512, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA512_HMAC, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA512_HMAC_GENERAL, {256, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA384_HMAC, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA384_HMAC_GENERAL, {192, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA256, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA256_HMAC, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA256_HMAC_GENERAL, {128, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA224, {0, 0, CKF_HW | CKF_DIGEST}}, {CKM_SHA224_HMAC, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA224_HMAC_GENERAL, {112, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA_1, {0, 0, CKF_DIGEST}}, {CKM_SHA_1_HMAC, {80, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_SHA_1_HMAC_GENERAL, {80, 2048, CKF_SIGN | CKF_VERIFY}}, {CKM_MD5, {0, 0, CKF_DIGEST}}, {CKM_EC_KEY_PAIR_GEN, {160, 521, CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, {CKM_ECDSA, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, {CKM_ECDSA_SHA1, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, {CKM_ECDSA_SHA224, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, {CKM_ECDSA_SHA256, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, {CKM_ECDSA_SHA384, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, {CKM_ECDSA_SHA512, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P}}, {CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}} }; static const CK_ULONG cca_mech_list_len = (sizeof(cca_mech_list) / sizeof(MECH_LIST_ELEMENT)); CK_RV token_specific_rng(STDLL_TokData_t * tokdata, CK_BYTE * output, CK_ULONG bytes) { long return_code, reason_code; unsigned char rule_array[CCA_KEYWORD_SIZE]; CK_ULONG bytes_so_far = 0, num_bytes; long rule_array_count = 1, zero = 0; CK_RV rv; UNUSED(tokdata); memcpy(rule_array, "RANDOM ", (size_t) CCA_KEYWORD_SIZE); while (bytes_so_far < bytes) { num_bytes = bytes - bytes_so_far; if (num_bytes > 8192) num_bytes = 8192; dll_CSNBRNGL(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &zero, NULL, (long *)&num_bytes, output + bytes_so_far); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBRNGL failed. return:%ld, reason:%ld\n", return_code, reason_code); rv = CKR_FUNCTION_FAILED; return rv; } bytes_so_far += num_bytes; } return CKR_OK; } static CK_RV cca_resolve_lib_sym(void *hdl) { char *error = NULL; dlerror(); /* Clear existing error */ *(void **)(&dll_CSNBCKI) = dlsym(hdl, "CSNBCKI"); *(void **)(&dll_CSNBCKM) = dlsym(hdl, "CSNBCKM"); *(void **)(&dll_CSNBDKX) = dlsym(hdl, "CSNBDKX"); *(void **)(&dll_CSNBDKM) = dlsym(hdl, "CSNBDKM"); *(void **)(&dll_CSNBMKP) = dlsym(hdl, "CSNBMKP"); *(void **)(&dll_CSNBKEX) = dlsym(hdl, "CSNBKEX"); *(void **)(&dll_CSNBKGN) = dlsym(hdl, "CSNBKGN"); *(void **)(&dll_CSNBKGN2) = dlsym(hdl, "CSNBKGN2"); *(void **)(&dll_CSNBKIM) = dlsym(hdl, "CSNBKIM"); *(void **)(&dll_CSNBKPI) = dlsym(hdl, "CSNBKPI"); *(void **)(&dll_CSNBKPI2) = dlsym(hdl, "CSNBKPI2"); *(void **)(&dll_CSNBKSI) = dlsym(hdl, "CSNBKSI"); *(void **)(&dll_CSNBKRC) = dlsym(hdl, "CSNBKRC"); *(void **)(&dll_CSNBAKRC) = dlsym(hdl, "CSNBAKRC"); *(void **)(&dll_CSNBKRD) = dlsym(hdl, "CSNBKRD"); *(void **)(&dll_CSNBKRL) = dlsym(hdl, "CSNBKRL"); *(void **)(&dll_CSNBKRR) = dlsym(hdl, "CSNBKRR"); *(void **)(&dll_CSNBKRW) = dlsym(hdl, "CSNBKRW"); *(void **)(&dll_CSNDKRC) = dlsym(hdl, "CSNDKRC"); *(void **)(&dll_CSNDKRD) = dlsym(hdl, "CSNDKRD"); *(void **)(&dll_CSNDKRL) = dlsym(hdl, "CSNDKRL"); *(void **)(&dll_CSNDKRR) = dlsym(hdl, "CSNDKRR"); *(void **)(&dll_CSNDKRW) = dlsym(hdl, "CSNDKRW"); *(void **)(&dll_CSNBKYT) = dlsym(hdl, "CSNBKYT"); *(void **)(&dll_CSNBKYTX) = dlsym(hdl, "CSNBKYTX"); *(void **)(&dll_CSNBKTC) = dlsym(hdl, "CSNBKTC"); *(void **)(&dll_CSNBKTR) = dlsym(hdl, "CSNBKTR"); *(void **)(&dll_CSNBRNG) = dlsym(hdl, "CSNBRNG"); *(void **)(&dll_CSNBRNGL) = dlsym(hdl, "CSNBRNGL"); *(void **)(&dll_CSNBSAE) = dlsym(hdl, "CSNBSAE"); *(void **)(&dll_CSNBSAD) = dlsym(hdl, "CSNBSAD"); *(void **)(&dll_CSNBDEC) = dlsym(hdl, "CSNBDEC"); *(void **)(&dll_CSNBENC) = dlsym(hdl, "CSNBENC"); *(void **)(&dll_CSNBMGN) = dlsym(hdl, "CSNBMGN"); *(void **)(&dll_CSNBMVR) = dlsym(hdl, "CSNBMVR"); *(void **)(&dll_CSNBKTB) = dlsym(hdl, "CSNBKTB"); *(void **)(&dll_CSNBKTB2) = dlsym(hdl, "CSNBKTB2"); *(void **)(&dll_CSNDPKG) = dlsym(hdl, "CSNDPKG"); *(void **)(&dll_CSNDPKB) = dlsym(hdl, "CSNDPKB"); *(void **)(&dll_CSNBOWH) = dlsym(hdl, "CSNBOWH"); *(void **)(&dll_CSNDPKI) = dlsym(hdl, "CSNDPKI"); *(void **)(&dll_CSNDDSG) = dlsym(hdl, "CSNDDSG"); *(void **)(&dll_CSNDDSV) = dlsym(hdl, "CSNDDSV"); *(void **)(&dll_CSNDKTC) = dlsym(hdl, "CSNDKTC"); *(void **)(&dll_CSNDPKX) = dlsym(hdl, "CSNDPKX"); *(void **)(&dll_CSNDSYI) = dlsym(hdl, "CSNDSYI"); *(void **)(&dll_CSNDSYX) = dlsym(hdl, "CSNDSYX"); *(void **)(&dll_CSUACFQ) = dlsym(hdl, "CSUACFQ"); *(void **)(&dll_CSUACFC) = dlsym(hdl, "CSUACFC"); *(void **)(&dll_CSNDSBC) = dlsym(hdl, "CSNDSBC"); *(void **)(&dll_CSNDSBD) = dlsym(hdl, "CSNDSBD"); *(void **)(&dll_CSUALCT) = dlsym(hdl, "CSUALCT"); *(void **)(&dll_CSUAACM) = dlsym(hdl, "CSUAACM"); *(void **)(&dll_CSUAACI) = dlsym(hdl, "CSUAACI"); *(void **)(&dll_CSNDPKH) = dlsym(hdl, "CSNDPKH"); *(void **)(&dll_CSNDPKR) = dlsym(hdl, "CSNDPKR"); *(void **)(&dll_CSUAMKD) = dlsym(hdl, "CSUAMKD"); *(void **)(&dll_CSNDRKD) = dlsym(hdl, "CSNDRKD"); *(void **)(&dll_CSNDRKL) = dlsym(hdl, "CSNDRKL"); *(void **)(&dll_CSNDSYG) = dlsym(hdl, "CSNDSYG"); *(void **)(&dll_CSNBPTR) = dlsym(hdl, "CSNBPTR"); *(void **)(&dll_CSNBCPE) = dlsym(hdl, "CSNBCPE"); *(void **)(&dll_CSNBCPA) = dlsym(hdl, "CSNBCPA"); *(void **)(&dll_CSNBPGN) = dlsym(hdl, "CSNBPGN"); *(void **)(&dll_CSNBPVR) = dlsym(hdl, "CSNBPVR"); *(void **)(&dll_CSNBDKG) = dlsym(hdl, "CSNBDKG"); *(void **)(&dll_CSNBEPG) = dlsym(hdl, "CSNBEPG"); *(void **)(&dll_CSNBCVE) = dlsym(hdl, "CSNBCVE"); *(void **)(&dll_CSNBCSG) = dlsym(hdl, "CSNBCSG"); *(void **)(&dll_CSNBCSV) = dlsym(hdl, "CSNBCSV"); *(void **)(&dll_CSNBCVG) = dlsym(hdl, "CSNBCVG"); *(void **)(&dll_CSNBKTP) = dlsym(hdl, "CSNBKTP"); *(void **)(&dll_CSNDPKE) = dlsym(hdl, "CSNDPKE"); *(void **)(&dll_CSNDPKD) = dlsym(hdl, "CSNDPKD"); *(void **)(&dll_CSNBPEX) = dlsym(hdl, "CSNBPEX"); *(void **)(&dll_CSNBPEXX) = dlsym(hdl, "CSNBPEXX"); *(void **)(&dll_CSUARNT) = dlsym(hdl, "CSUARNT"); *(void **)(&dll_CSNBCVT) = dlsym(hdl, "CSNBCVT"); *(void **)(&dll_CSNBMDG) = dlsym(hdl, "CSNBMDG"); *(void **)(&dll_CSUACRA) = dlsym(hdl, "CSUACRA"); *(void **)(&dll_CSUACRD) = dlsym(hdl, "CSUACRD"); *(void **)(&dll_CSNBTRV) = dlsym(hdl, "CSNBTRV"); *(void **)(&dll_CSNBSKY) = dlsym(hdl, "CSNBSKY"); *(void **)(&dll_CSNBSPN) = dlsym(hdl, "CSNBSPN"); *(void **)(&dll_CSNBPCU) = dlsym(hdl, "CSNBPCU"); *(void **)(&dll_CSUAPCV) = dlsym(hdl, "CSUAPCV"); *(void **)(&dll_CSUAPRB) = dlsym(hdl, "CSUAPRB"); *(void **)(&dll_CSUADHK) = dlsym(hdl, "CSUADHK"); *(void **)(&dll_CSUADHQ) = dlsym(hdl, "CSUADHQ"); *(void **)(&dll_CSNDTBC) = dlsym(hdl, "CSNDTBC"); *(void **)(&dll_CSNDRKX) = dlsym(hdl, "CSNDRKX"); *(void **)(&dll_CSNBKET) = dlsym(hdl, "CSNBKET"); *(void **)(&dll_CSNBHMG) = dlsym(hdl, "CSNBHMG"); *(void **)(&dll_CSNBHMV) = dlsym(hdl, "CSNBHMV"); *(void **)(&dll_CSNBCTT2) = dlsym(hdl, "CSNBCTT2"); if ((error = dlerror()) != NULL) { OCK_SYSLOG(LOG_ERR, "%s\n", error); exit(EXIT_FAILURE); } return CKR_OK; } CK_RV token_specific_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, char *conf_name) { unsigned char rule_array[256] = { 0, }; long return_code, reason_code, rule_array_count, verb_data_length; void *lib_csulcca; CK_RV rc; UNUSED(conf_name); TRACE_INFO("cca %s slot=%lu running\n", __func__, SlotNumber); tokdata->mech_list = (MECH_LIST_ELEMENT *)cca_mech_list; tokdata->mech_list_len = cca_mech_list_len; lib_csulcca = dlopen(CCASHAREDLIB, RTLD_GLOBAL | RTLD_NOW); if (lib_csulcca == NULL) { OCK_SYSLOG(LOG_ERR, "%s: Error loading library: '%s' [%s]\n", __func__, CCASHAREDLIB, dlerror()); TRACE_ERROR("%s: Error loading shared library '%s' [%s]\n", __func__, CCASHAREDLIB, dlerror()); return CKR_FUNCTION_FAILED; } rc = cca_resolve_lib_sym(lib_csulcca); if (rc) exit(rc); memcpy(rule_array, "STATCCAE", 8); rule_array_count = 1; verb_data_length = 0; dll_CSUACFQ(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &verb_data_length, NULL); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSUACFQ failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } /* This value should be 2 if the master key is set in the card */ if (memcmp(&rule_array[CCA_STATCCAE_SYM_CMK_OFFSET], "2 ", 8)) { OCK_SYSLOG(LOG_WARNING, "Warning: CCA symmetric master key is not yet loaded"); } if (memcmp(&rule_array[CCA_STATCCAE_ASYM_CMK_OFFSET], "2 ", 8)) { OCK_SYSLOG(LOG_WARNING, "Warning: CCA asymmetric master key is not yet loaded"); } return CKR_OK; } CK_RV token_specific_final(STDLL_TokData_t *tokdata, CK_BBOOL in_fork_initializer) { UNUSED(tokdata); UNUSED(in_fork_initializer); TRACE_INFO("cca %s running\n", __func__); return CKR_OK; } static CK_RV cca_key_gen(enum cca_key_type type, CK_BYTE * key, unsigned char *key_form, unsigned char *key_type_1, CK_ULONG key_size) { long return_code, reason_code; unsigned char key_length[CCA_KEYWORD_SIZE]; unsigned char key_type_2[CCA_KEYWORD_SIZE] = { 0, }; unsigned char kek_key_identifier_1[CCA_KEY_ID_SIZE] = { 0, }; unsigned char kek_key_identifier_2[CCA_KEY_ID_SIZE] = { 0, }; unsigned char generated_key_identifier_2[CCA_KEY_ID_SIZE] = { 0, }; if (type == CCA_DES_KEY) { switch (key_size) { case 8: memcpy(key_length, "KEYLN8 ", (size_t) CCA_KEYWORD_SIZE); break; case 24: memcpy(key_length, "KEYLN24 ", (size_t) CCA_KEYWORD_SIZE); break; default: TRACE_ERROR("Invalid key length: %lu\n", key_size); return CKR_KEY_SIZE_RANGE; } } else if (type == CCA_AES_KEY) { switch (key_size) { case 16: memcpy(key_length, "KEYLN16 ", CCA_KEYWORD_SIZE); break; case 24: memcpy(key_length, "KEYLN24 ", (size_t) CCA_KEYWORD_SIZE); break; case 32: memcpy(key_length, " ", (size_t) CCA_KEYWORD_SIZE); break; default: TRACE_ERROR("Invalid key length: %lu\n", key_size); return CKR_KEY_SIZE_RANGE; } } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } dll_CSNBKGN(&return_code, &reason_code, NULL, NULL, key_form, key_length, key_type_1, key_type_2, kek_key_identifier_1, kek_key_identifier_2, key, generated_key_identifier_2); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKGN(KEYGEN) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } return CKR_OK; } CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **des_key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { unsigned char key_form[CCA_KEYWORD_SIZE]; unsigned char key_type_1[CCA_KEYWORD_SIZE]; UNUSED(tokdata); *des_key = calloc(CCA_KEY_ID_SIZE, 1); if (*des_key == NULL) return CKR_HOST_MEMORY; *len = CCA_KEY_ID_SIZE; *is_opaque = TRUE; memcpy(key_form, "OP ", (size_t) CCA_KEYWORD_SIZE); memcpy(key_type_1, "DATA ", (size_t) CCA_KEYWORD_SIZE); return cca_key_gen(CCA_DES_KEY, *des_key, key_form, key_type_1, keysize); } CK_RV token_specific_des_ecb(STDLL_TokData_t * tokdata, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key, CK_BYTE encrypt) { UNUSED(tokdata); UNUSED(in_data); UNUSED(in_data_len); UNUSED(out_data); UNUSED(out_data_len); UNUSED(key); UNUSED(encrypt); TRACE_INFO("Unsupported function reached.\n"); return CKR_FUNCTION_NOT_SUPPORTED; } CK_RV token_specific_des_cbc(STDLL_TokData_t * tokdata, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key, CK_BYTE * init_v, CK_BYTE encrypt) { long return_code, reason_code, rule_array_count, length; long pad_character = 0; //char iv[8] = { 0xfe, 0x43, 0x12, 0xed, 0xaa, 0xbb, 0xdd, 0x90 }; unsigned char chaining_vector[CCA_OCV_SIZE]; unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; CK_BYTE *local_out = out_data; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); if (template_attribute_find(key->template, CKA_IBM_OPAQUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return CKR_FUNCTION_FAILED; } /* We need to have 8 bytes more than the in data length in case CCA * adds some padding, although this extra 8 bytes may not be needed. * If *out_data_len is not 8 bytes larger than in_data_len, then * we'll malloc the needed space and get the data back from CCA in this * malloc'd buffer. If it turns out that the extra 8 bytes wasn't * needed, we just silently copy the data to the user's buffer and * free our malloc'd space, returning as normal. If the space was * needed, we return an error and no memory corruption happens. */ if (*out_data_len < (in_data_len + 8)) { local_out = malloc(in_data_len + 8); if (!local_out) { TRACE_ERROR("Malloc of %lu bytes failed.\n", in_data_len + 8); return CKR_HOST_MEMORY; } } length = in_data_len; rule_array_count = 1; memcpy(rule_array, "CBC ", (size_t) CCA_KEYWORD_SIZE); if (encrypt) { dll_CSNBENC(&return_code, &reason_code, NULL, NULL, attr->pValue, //id, &length, in_data, //in, init_v, //iv, &rule_array_count, rule_array, &pad_character, chaining_vector, local_out); //out_data); //out); } else { dll_CSNBDEC(&return_code, &reason_code, NULL, NULL, attr->pValue, //id, &length, in_data, //in, init_v, //iv, &rule_array_count, rule_array, chaining_vector, local_out); //out_data); //out); } if (return_code != CCA_SUCCESS) { if (encrypt) TRACE_ERROR("CSNBENC (DES ENCRYPT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); else TRACE_ERROR("CSNBDEC (DES DECRYPT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (out_data != local_out) free(local_out); return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { if (encrypt) TRACE_WARNING("CSNBENC (DES ENCRYPT) succeeded, but" " returned reason:%ld\n", reason_code); else TRACE_WARNING("CSNBDEC (DES DECRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } /* If we malloc'd a new buffer due to overflow concerns and the data * coming out turned out to be bigger than expected, return an error. * * Else, memcpy the data back to the user's buffer */ if ((local_out != out_data) && ((CK_ULONG) length > *out_data_len)) { TRACE_DEVEL("CKR_BUFFER_TOO_SMALL: %ld bytes to write into %ld " "bytes space\n", length, *out_data_len); TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); free(local_out); return CKR_BUFFER_TOO_SMALL; } else if (local_out != out_data) { memcpy(out_data, local_out, (size_t) length); free(local_out); } *out_data_len = length; return CKR_OK; } CK_RV token_specific_tdes_ecb(STDLL_TokData_t * tokdata, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key, CK_BYTE encrypt) { UNUSED(tokdata); UNUSED(in_data); UNUSED(in_data_len); UNUSED(out_data); UNUSED(out_data_len); UNUSED(key); UNUSED(encrypt); TRACE_WARNING("Unsupported function reached.\n"); return CKR_FUNCTION_NOT_SUPPORTED; } CK_RV token_specific_tdes_cbc(STDLL_TokData_t * tokdata, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key, CK_BYTE * init_v, CK_BYTE encrypt) { /* Since keys are opaque objects in this token and there's only * one encipher command to CCA, we can just pass through */ return token_specific_des_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, encrypt); } uint16_t cca_inttok_privkey_get_len(CK_BYTE * tok) { return *(uint16_t *) & tok[CCA_RSA_INTTOK_PRIVKEY_LENGTH_OFFSET]; } /* Given a CCA internal token private key object, get the modulus */ CK_RV cca_inttok_privkey_get_n(CK_BYTE * tok, CK_ULONG * n_len, CK_BYTE * n) { uint16_t n_length; n_length = *(uint16_t *) &tok[CCA_RSA_INTTOK_PRIVKEY_N_LENGTH_OFFSET]; if (n_length > (*n_len)) { TRACE_ERROR("Not enough room to return n.(Got %lu, need %hu)\n", *n_len, n_length); return CKR_FUNCTION_FAILED; } memcpy(n, &tok[CCA_RSA_INTTOK_PRIVKEY_N_OFFSET], (size_t) n_length); *n_len = n_length; return CKR_OK; } /* Given a CCA internal token pubkey object, get the public exponent */ CK_RV cca_inttok_pubkey_get_e(CK_BYTE * tok, CK_ULONG * e_len, CK_BYTE * e) { uint16_t e_length; e_length = *(uint16_t *) & tok[CCA_RSA_INTTOK_PUBKEY_E_LENGTH_OFFSET]; if (e_length > (*e_len)) { TRACE_ERROR("Not enough room to return e.(Got %lu, need %hu)\n", *e_len, e_length); return CKR_FUNCTION_FAILED; } memcpy(e, &tok[CCA_RSA_INTTOK_PUBKEY_E_OFFSET], (size_t) e_length); *e_len = (CK_ULONG) e_length; return CKR_OK; } CK_RV token_create_keypair_object(TEMPLATE * tmpl, CK_ULONG tok_len, CK_BYTE * tok) { uint16_t privkey_len, pubkey_offset; CK_BYTE n[CCATOK_MAX_N_LEN], e[CCATOK_MAX_E_LEN]; CK_ULONG n_len = CCATOK_MAX_N_LEN, e_len = CCATOK_MAX_E_LEN; CK_ATTRIBUTE *modulus, *pub_exp, *opaque_key; CK_RV rv; privkey_len = cca_inttok_privkey_get_len(&tok[CCA_RSA_INTTOK_PRIVKEY_OFFSET]); pubkey_offset = privkey_len + CCA_RSA_INTTOK_HDR_LENGTH; /* That's right, n is stored in the private key area. Get it there */ if ((rv = cca_inttok_privkey_get_n(&tok[CCA_RSA_INTTOK_PRIVKEY_OFFSET], &n_len, n))) { TRACE_DEVEL("cca_inttok_privkey_get_n() failed. rv=0x%lx\n", rv); return rv; } /* Get e */ if ((rv = cca_inttok_pubkey_get_e(&tok[pubkey_offset], &e_len, e))) { TRACE_DEVEL("cca_inttok_pubkey_get_e() failed. rv=0x%lx\n", rv); return rv; } /* Add n's value to the template */ if ((rv = build_attribute(CKA_MODULUS, n, n_len, &modulus))) { TRACE_DEVEL("build_attribute for n failed. rv=0x%lx\n", rv); return rv; } template_update_attribute(tmpl, modulus); /* Add e's value to the template */ if ((rv = build_attribute(CKA_PUBLIC_EXPONENT, e, e_len, &pub_exp))) { TRACE_DEVEL("build_attribute for e failed. rv=0x%lx\n", rv); return rv; } template_update_attribute(tmpl, pub_exp); /* Add the opaque key object to the template */ if ((rv = build_attribute(CKA_IBM_OPAQUE, tok, tok_len, &opaque_key))) { TRACE_DEVEL("build_attribute for opaque key failed. rv=0x%lx\n", rv); return rv; } template_update_attribute(tmpl, opaque_key); return CKR_OK; } #if 0 CK_RV token_create_priv_key(TEMPLATE * priv_tmpl, CK_ULONG tok_len, CK_BYTE * tok) { CK_BYTE n[CCATOK_MAX_N_LEN]; CK_ULONG n_len = CCATOK_MAX_N_LEN; CK_RV rv; CK_ATTRIBUTE *opaque_key, *modulus; /* That's right, n is stored in the private key area. Get it there */ if ((rv = cca_inttok_privkey_get_n(&tok[CCA_RSA_INTTOK_PRIVKEY_OFFSET], &n_len, n))) { TRACE_DEVEL("cca_inttok_privkey_get_n() failed. rv=0x%lx", rv); return rv; } /* Add n's value to the template. We need to do this for the private * key as well as the public key because openCryptoki checks data * sizes against the size of the CKA_MODULUS attribute of whatever * key object it gets */ if ((rv = build_attribute(CKA_MODULUS, n, n_len, &modulus))) { TRACE_DEVEL("build_attribute for n failed. rv=0x%lx", rv); return rv; } template_update_attribute(priv_tmpl, modulus); /* Add the opaque key object to the template */ if ((rv = build_attribute(CKA_IBM_OPAQUE, tok, tok_len, &opaque_key))) { TRACE_DEVEL("build_attribute for opaque key failed. rv=0x%lx", rv); return rv; } template_update_attribute(priv_tmpl, opaque_key); return CKR_OK; } #endif CK_RV token_specific_rsa_generate_keypair(STDLL_TokData_t * tokdata, TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long key_value_structure_length; long private_key_name_length, key_token_length; unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; long regeneration_data_length, generated_key_token_length; unsigned char regeneration_data[CCA_REGENERATION_DATA_SIZE] = { 0, }; unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; unsigned char generated_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; uint16_t size_of_e; uint16_t mod_bits; CK_ATTRIBUTE *pub_exp = NULL, *attr = NULL; CK_RV rv; CK_BYTE_PTR ptr; CK_ULONG tmpsize, tmpexp; UNUSED(tokdata); if (!template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr)) { TRACE_ERROR("Could not find CKA_MODULUS_BITS for the key.\n"); return CKR_TEMPLATE_INCOMPLETE; } mod_bits = *(CK_ULONG *) attr->pValue; /* If e is specified in the template, use it */ rv = template_attribute_find(publ_tmpl, CKA_PUBLIC_EXPONENT, &pub_exp); if (rv == TRUE) { /* Per CCA manual, we really only support 3 values here: * * * 0 (generate random public exponent) * * * 3 or * * * 65537 * * Trim the P11 value so we can check what's comming our way */ tmpsize = pub_exp->ulValueLen; ptr = p11_bigint_trim(pub_exp->pValue, &tmpsize); /* If we trimmed the number correctly, only 3 bytes are * * sufficient to hold 65537 (0x010001) */ if (tmpsize > 3) return CKR_TEMPLATE_INCONSISTENT; /* make pValue into CK_ULONG so we can compare */ tmpexp = 0; memcpy((unsigned char *) &tmpexp + sizeof(CK_ULONG) - tmpsize, ptr, tmpsize); /* right align */ /* Check for one of the three allowed values */ if ((tmpexp != 0) && (tmpexp != 3) && (tmpexp != 65537)) return CKR_TEMPLATE_INCONSISTENT; size_of_e = (uint16_t) tmpsize; memcpy(&key_value_structure[CCA_PKB_E_SIZE_OFFSET], &size_of_e, (size_t) CCA_PKB_E_SIZE); memcpy(&key_value_structure[CCA_PKB_E_OFFSET], ptr, (size_t) tmpsize); } key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; memcpy(key_value_structure, &mod_bits, sizeof(uint16_t)); /* One last check. CCA can't auto-generate a random public * * exponent if the modulus length is more than 2048 bits * * We should be ok checking the public exponent length in the * * key_value_structure, since either the caller never * * specified it or we trimmed it's size. The size should be * * zero if the value is zero in both cases. * * public exponent has CCA_PKB_E_SIZE_OFFSET offset with * * 2-bytes size */ if (mod_bits > 2048 && key_value_structure[CCA_PKB_E_SIZE_OFFSET] == 0x00 && key_value_structure[CCA_PKB_E_SIZE_OFFSET + 1] == 0x00) { return CKR_TEMPLATE_INCONSISTENT; } rule_array_count = 2; memcpy(rule_array, "RSA-AESCKEY-MGMT", (size_t) (CCA_KEYWORD_SIZE * 2)); private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, &key_token_length, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } rule_array_count = 1; memset(rule_array, 0, sizeof(rule_array)); memcpy(rule_array, "MASTER ", (size_t) CCA_KEYWORD_SIZE); generated_key_token_length = CCA_KEY_TOKEN_SIZE; regeneration_data_length = 0; dll_CSNDPKG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, ®eneration_data_length, regeneration_data, &key_token_length, key_token, transport_key_identifier, &generated_key_token_length, generated_key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKG (RSA KEY GENERATE) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } TRACE_DEVEL("RSA secure key token generated. size: %ld\n", generated_key_token_length); rv = token_create_keypair_object(publ_tmpl, generated_key_token_length, generated_key_token); if (rv != CKR_OK) { TRACE_DEVEL("token_create_keypair_object failed. rv:%lu\n", rv); return rv; } rv = token_create_keypair_object(priv_tmpl, generated_key_token_length, generated_key_token); if (rv != CKR_OK) TRACE_DEVEL("token_create_keypair_object failed. rv:%lu\n", rv); return rv; } CK_RV token_specific_rsa_encrypt(STDLL_TokData_t * tokdata, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key_obj) { long return_code, reason_code, rule_array_count, data_structure_length; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; UNUSED(tokdata); /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } /* The max value allowable by CCA for out_data_len is 512, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ if (*out_data_len > 512) *out_data_len = 512; rule_array_count = 1; memcpy(rule_array, "PKCS-1.2", CCA_KEYWORD_SIZE); data_structure_length = 0; dll_CSNDPKE(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &in_data_len, in_data, &data_structure_length, // must be 0 NULL, // ignored (long *) &(attr->ulValueLen), attr->pValue, (long *) out_data_len, out_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKE (RSA ENCRYPT) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { TRACE_WARNING("CSNDPKE (RSA ENCRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } return CKR_OK; } CK_RV token_specific_rsa_decrypt(STDLL_TokData_t * tokdata, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key_obj) { long return_code, reason_code, rule_array_count, data_structure_length; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; UNUSED(tokdata); /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } /* The max value allowable by CCA for out_data_len is 512, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ if (*out_data_len > 512) *out_data_len = 512; rule_array_count = 1; memcpy(rule_array, "PKCS-1.2", CCA_KEYWORD_SIZE); data_structure_length = 0; dll_CSNDPKD(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &in_data_len, in_data, &data_structure_length, // must be 0 NULL, // ignored (long *) &(attr->ulValueLen), attr->pValue, (long *) out_data_len, out_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKD (RSA DECRYPT) failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { TRACE_WARNING("CSNDPKD (RSA DECRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } return CKR_OK; } CK_RV token_specific_rsa_oaep_encrypt(STDLL_TokData_t *tokdata, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *hash, CK_ULONG hlen) { CK_RSA_PKCS_OAEP_PARAMS *oaep; long return_code, reason_code, rule_array_count, data_structure_length; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; OBJECT *key_obj = NULL; CK_RV rc; UNUSED(tokdata); UNUSED(hash); UNUSED(hlen); rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); goto done; } /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } oaep = (CK_RSA_PKCS_OAEP_PARAMS *)ctx->mech.pParameter; if (oaep == NULL || ctx->mech.ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source data\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } /* The max value allowable by CCA for out_data_len is 512, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ if (*out_data_len > 512) *out_data_len = 512; rule_array_count = 2; switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCSOAEPSHA-1 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCSOAEPSHA-256 ", 2 * CCA_KEYWORD_SIZE); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } data_structure_length = 0; dll_CSNDPKE(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&in_data_len, in_data, &data_structure_length, // must be 0 NULL, // ignored (long *)&(attr->ulValueLen), attr->pValue, (long *)out_data_len, out_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKE (RSA ENCRYPT) failed. return:%ld, reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; goto done; } else if (reason_code != 0) { TRACE_WARNING("CSNDPKE (RSA ENCRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV token_specific_rsa_oaep_decrypt(STDLL_TokData_t *tokdata, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *hash, CK_ULONG hlen) { CK_RSA_PKCS_OAEP_PARAMS *oaep; long return_code, reason_code, rule_array_count, data_structure_length; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; OBJECT *key_obj = NULL; CK_RV rc; UNUSED(tokdata); UNUSED(hash); UNUSED(hlen); rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); goto done; } /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } oaep = (CK_RSA_PKCS_OAEP_PARAMS *)ctx->mech.pParameter; if (oaep == NULL || ctx->mech.ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source data\n"); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } /* The max value allowable by CCA for out_data_len is 512, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ if (*out_data_len > 512) *out_data_len = 512; rule_array_count = 2; switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCSOAEPSHA-1 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCSOAEPSHA-256 ", 2 * CCA_KEYWORD_SIZE); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } data_structure_length = 0; dll_CSNDPKD(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&in_data_len, in_data, &data_structure_length, // must be 0 NULL, // ignored (long *) &(attr->ulValueLen), attr->pValue, (long *)out_data_len, out_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKD (RSA DECRYPT) failed. return:%ld, reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; goto done; } else if (reason_code != 0) { TRACE_WARNING("CSNDPKD (RSA DECRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV token_specific_rsa_sign(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key_obj) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long signature_bit_length; CK_ATTRIBUTE *attr; UNUSED(tokdata); UNUSED(sess); /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } /* The max value allowable by CCA for out_data_len is 512, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ if (*out_data_len > 512) *out_data_len = 512; rule_array_count = 1; memcpy(rule_array, "PKCS-1.1", CCA_KEYWORD_SIZE); dll_CSNDDSG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &(attr->ulValueLen), attr->pValue, (long *) &in_data_len, in_data, (long *) out_data_len, &signature_bit_length, out_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (RSA SIGN) failed. return :%ld, reason: %ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { TRACE_WARNING("CSNDDSG (RSA SIGN) succeeded, but " "returned reason: %ld\n", reason_code); } return CKR_OK; } CK_RV token_specific_rsa_verify(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG out_data_len, OBJECT * key_obj) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; UNUSED(tokdata); UNUSED(sess); /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } /* The max value allowable by CCA for out_data_len is 512, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ if (out_data_len > 512) out_data_len = 512; rule_array_count = 1; memcpy(rule_array, "PKCS-1.1", CCA_KEYWORD_SIZE); dll_CSNDDSV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &(attr->ulValueLen), attr->pValue, (long *) &in_data_len, in_data, (long *) &out_data_len, out_data); if (return_code == 4 && reason_code == 429) { return CKR_SIGNATURE_INVALID; } else if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSV (RSA VERIFY) failed. return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 72) { /* * Return CKR_SIGNATURE_INVALID in case of return code 8 and * reason code 72 because we dont know why the RSA op failed * and it may have failed due to a tampered signature being * greater or equal to the modulus. */ return CKR_SIGNATURE_INVALID; } return CKR_FUNCTION_FAILED; } if (reason_code != 0) { TRACE_WARNING("CSNDDSV (RSA VERIFY) succeeded, but" " returned reason:%ld\n", reason_code); } return CKR_OK; } CK_RV token_specific_rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_RSA_PKCS_PSS_PARAMS *pss; long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long signature_bit_length, message_len; CK_ATTRIBUTE *attr; OBJECT *key_obj = NULL; CK_BYTE *message = NULL; CK_RV rc; UNUSED(tokdata); UNUSED(sess); rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); goto done; } /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } pss = (CK_RSA_PKCS_PSS_PARAMS *)ctx->mech.pParameter; if (pss == NULL || ctx->mech.ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } message_len = 4 + in_data_len; message = malloc(message_len); if (message == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } *((uint32_t *)message) = htonl(pss->sLen); memcpy(message + 4, in_data, in_data_len); /* The max value allowable by CCA for out_data_len is 512, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ if (*out_data_len > 512) *out_data_len = 512; rule_array_count = 2; switch (pss->hashAlg) { case CKM_SHA_1: if (pss->mgf != CKG_MGF1_SHA1) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-1 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA224: if (pss->mgf != CKG_MGF1_SHA224) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-224 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (pss->mgf != CKG_MGF1_SHA256) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-256 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA384: if (pss->mgf != CKG_MGF1_SHA384) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-384 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA512: if (pss->mgf != CKG_MGF1_SHA512) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-512 ", 2 * CCA_KEYWORD_SIZE); break; } dll_CSNDDSG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&(attr->ulValueLen), attr->pValue, &message_len, message, (long *)out_data_len, &signature_bit_length, out_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (RSA PSS SIGN) failed. return :%ld, reason: %ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; goto done; } else if (reason_code != 0) { TRACE_WARNING("CSNDDSG (RSA PSS SIGN) succeeded, but " "returned reason: %ld\n", reason_code); } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (message != NULL) free(message); return rc; } CK_RV token_specific_rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG out_data_len) { CK_RSA_PKCS_PSS_PARAMS *pss; long return_code, reason_code, rule_array_count, message_len; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; OBJECT *key_obj = NULL; CK_BYTE *message = NULL; CK_RV rc; UNUSED(tokdata); UNUSED(sess); rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); goto done; } /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); rc = CKR_TEMPLATE_INCOMPLETE; goto done; } pss = (CK_RSA_PKCS_PSS_PARAMS *)ctx->mech.pParameter; if (pss == NULL || ctx->mech.ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } message_len = 4 + in_data_len; message = malloc(message_len); if (message == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } *((uint32_t *)message) = pss->sLen; memcpy(message + 4, in_data, in_data_len); /* The max value allowable by CCA for out_data_len is 512, so cap the * incoming value if its too large. CCA will throw error 8, 72 otherwise. */ if (out_data_len > 512) out_data_len = 512; rule_array_count = 2; switch (pss->hashAlg) { case CKM_SHA_1: if (pss->mgf != CKG_MGF1_SHA1) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-1 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA224: if (pss->mgf != CKG_MGF1_SHA224) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-224 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (pss->mgf != CKG_MGF1_SHA256) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-256 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA384: if (pss->mgf != CKG_MGF1_SHA384) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-384 ", 2 * CCA_KEYWORD_SIZE); break; case CKM_SHA512: if (pss->mgf != CKG_MGF1_SHA512) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } memcpy(rule_array, "PKCS-PSSSHA-512 ", 2 * CCA_KEYWORD_SIZE); break; } dll_CSNDDSV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&(attr->ulValueLen), attr->pValue, &message_len, message, (long *)&out_data_len, out_data); if (return_code == 4 && reason_code == 429) { rc = CKR_SIGNATURE_INVALID; goto done; } else if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSV (RSA PSS VERIFY) failed. return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 72) { /* * Return CKR_SIGNATURE_INVALID in case of return code 8 and * reason code 72 because we dont know why the RSA op failed * and it may have failed due to a tampered signature being * greater or equal to the modulus. */ rc = CKR_SIGNATURE_INVALID; goto done; } rc = CKR_FUNCTION_FAILED; goto done; } if (reason_code != 0) { TRACE_WARNING("CSNDDSV (RSA PSS VERIFY) succeeded, but" " returned reason:%ld\n", reason_code); } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (message != NULL) free(message); return rc; } #ifndef NOAES CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **aes_key, CK_ULONG *len, CK_ULONG key_size, CK_BBOOL *is_opaque) { long return_code, reason_code; unsigned char key_token[CCA_KEY_ID_SIZE] = { 0, }; unsigned char key_form[CCA_KEYWORD_SIZE]; unsigned char key_type[CCA_KEYWORD_SIZE]; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0x20, }; long exit_data_len = 0, rule_array_count; unsigned char exit_data[4] = { 0, }; unsigned char reserved_1[4] = { 0, }; unsigned char point_to_array_of_zeros = 0; unsigned char mkvp[16] = { 0, }; UNUSED(tokdata); *aes_key = calloc(CCA_KEY_ID_SIZE, 1); if (*aes_key == NULL) return CKR_HOST_MEMORY; *len = CCA_KEY_ID_SIZE; *is_opaque = TRUE; memcpy(rule_array, "INTERNALAES NO-KEY ", (size_t) (CCA_KEYWORD_SIZE * 3)); memcpy(key_type, "DATA ", (size_t) CCA_KEYWORD_SIZE); switch (key_size) { case 16: memcpy(rule_array + 3 * CCA_KEYWORD_SIZE, "KEYLN16 ", CCA_KEYWORD_SIZE); break; case 24: memcpy(rule_array + 3 * CCA_KEYWORD_SIZE, "KEYLN24 ", (size_t) CCA_KEYWORD_SIZE); break; case 32: memcpy(rule_array + 3 * CCA_KEYWORD_SIZE, "KEYLN32 ", (size_t) CCA_KEYWORD_SIZE); break; default: TRACE_ERROR("Invalid key length: %lu\n", key_size); return CKR_KEY_SIZE_RANGE; } rule_array_count = 4; dll_CSNBKTB(&return_code, &reason_code, &exit_data_len, exit_data, key_token, key_type, &rule_array_count, rule_array, NULL, reserved_1, NULL, &point_to_array_of_zeros, NULL, NULL, NULL, NULL, mkvp); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBTKB (TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(key_form, "OP ", (size_t) CCA_KEYWORD_SIZE); memcpy(key_type, "AESTOKEN", (size_t) CCA_KEYWORD_SIZE); memcpy(*aes_key, key_token, (size_t) CCA_KEY_ID_SIZE); return cca_key_gen(CCA_AES_KEY, *aes_key, key_form, key_type, key_size); } CK_RV token_specific_aes_ecb(STDLL_TokData_t * tokdata, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key, CK_BYTE encrypt) { long return_code, reason_code, rule_array_count; long block_size = 16; unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; long opt_data_len = 0, key_params_len = 0, exit_data_len = 0, IV_len = 0, chain_vector_len = 0; unsigned char exit_data[1]; CK_BYTE *local_out = out_data; CK_ATTRIBUTE *attr = NULL; long int key_len; UNUSED(tokdata); if (template_attribute_find(key->template, CKA_IBM_OPAQUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return CKR_FUNCTION_FAILED; } key_len = 64; rule_array_count = 4; memcpy(rule_array, "AES ECB KEYIDENTINITIAL ", rule_array_count * (size_t) CCA_KEYWORD_SIZE); if (encrypt) { dll_CSNBSAE(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &key_params_len, NULL, &block_size, &IV_len, NULL, &chain_vector_len, NULL, (long int *)&in_data_len, in_data, (long int *)out_data_len, local_out, &opt_data_len, NULL); } else { dll_CSNBSAD(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &key_params_len, NULL, &block_size, &IV_len, NULL, &chain_vector_len, NULL, (long int *)&in_data_len, in_data, (long int *)out_data_len, local_out, &opt_data_len, NULL); } if (return_code != CCA_SUCCESS) { if (encrypt) { TRACE_ERROR("CSNBSAE (AES ENCRYPT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); } else { TRACE_ERROR("CSNBSAD (AES DECRYPT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); } (*out_data_len) = 0; return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { if (encrypt) { TRACE_WARNING("CSNBSAE (AES ENCRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } else { TRACE_WARNING("CSNBSAD (AES DECRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } } return CKR_OK; } CK_RV token_specific_aes_cbc(STDLL_TokData_t * tokdata, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key, CK_BYTE * init_v, CK_BYTE encrypt) { long return_code, reason_code, rule_array_count, length; long block_size = 16; unsigned char chaining_vector[32]; unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; long opt_data_len = 0, key_params_len = 0, exit_data_len = 0, IV_len = 16, chain_vector_len = 32; CK_BYTE *local_out = out_data; unsigned char exit_data[1]; CK_ATTRIBUTE *attr = NULL; long int key_len; UNUSED(tokdata); // get the key value if (template_attribute_find(key->template, CKA_IBM_OPAQUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (in_data_len % 16 == 0) { rule_array_count = 3; memcpy(rule_array, "AES KEYIDENTINITIAL ", rule_array_count * (size_t) CCA_KEYWORD_SIZE); } else { if ((encrypt) && (*out_data_len < (in_data_len + 16))) { local_out = malloc(in_data_len + 16); if (!local_out) { TRACE_ERROR("Malloc of %lu bytes failed.\n", in_data_len + 16); return CKR_HOST_MEMORY; } } rule_array_count = 3; memcpy(rule_array, "AES PKCS-PADKEYIDENT", rule_array_count * (size_t) CCA_KEYWORD_SIZE); } length = in_data_len; key_len = 64; if (encrypt) { dll_CSNBSAE(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &key_params_len, exit_data, &block_size, &IV_len, init_v, &chain_vector_len, chaining_vector, &length, in_data, (long int *)out_data_len, local_out, &opt_data_len, NULL); } else { dll_CSNBSAD(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_len, attr->pValue, &key_params_len, NULL, &block_size, &IV_len, init_v, &chain_vector_len, chaining_vector, &length, in_data, (long int *)out_data_len, local_out, &opt_data_len, NULL); } if (return_code != CCA_SUCCESS) { if (encrypt) { TRACE_ERROR("CSNBSAE (AES ENCRYPT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); } else { TRACE_ERROR("CSNBSAD (AES DECRYPT) failed. return:%ld," " reason:%ld\n", return_code, reason_code); } (*out_data_len) = 0; if (local_out != out_data) free(local_out); return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { if (encrypt) { TRACE_WARNING("CSNBSAE (AES ENCRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } else { TRACE_WARNING("CSNBSAD (AES DECRYPT) succeeded, but" " returned reason:%ld\n", reason_code); } } /* If we malloc'd a new buffer due to overflow concerns and the data * coming out turned out to be bigger than expected, return an error. * * Else, memcpy the data back to the user's buffer */ if ((local_out != out_data) && ((CK_ULONG) length > *out_data_len)) { TRACE_ERROR("buffer too small: %ld bytes to write into %ld " "bytes space\n", length, *out_data_len); free(local_out); return CKR_BUFFER_TOO_SMALL; } else if (local_out != out_data) { memcpy(out_data, local_out, (size_t) length); free(local_out); } *out_data_len = length; return CKR_OK; } #endif /* See the top of this file for the declarations of mech_list and * mech_list_len. */ CK_RV token_specific_get_mechanism_list(STDLL_TokData_t * tokdata, CK_MECHANISM_TYPE * pMechanismList, CK_ULONG * pulCount) { return ock_generic_get_mechanism_list(tokdata, pMechanismList, pulCount); } CK_RV token_specific_get_mechanism_info(STDLL_TokData_t * tokdata, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO * pInfo) { return ock_generic_get_mechanism_info(tokdata, type, pInfo); } CK_RV build_update_attribute(TEMPLATE * tmpl, CK_ATTRIBUTE_TYPE type, CK_BYTE * data, CK_ULONG data_len) { CK_ATTRIBUTE *attr; CK_RV rv; if ((rv = build_attribute(type, data, data_len, &attr))) { TRACE_DEVEL("Build attribute for type=%lu failed rv=0x%lx\n", type, rv); return rv; } template_update_attribute(tmpl, attr); return CKR_OK; } CK_BBOOL is_curve_error(long return_code, long reason_code) { if (return_code == 8) { /* * The following reason codes denote that the curve is not supported * 8 874 (36A) Error in Cert processing. Elliptic Curve is not * supported. * 8 2158 (86E) There is a mismatch between ECC key tokens of curve * types, key lengths, or both. Curve types and key * lengths must match. * 8 6015 (177F) An ECC curve type is invalid or its usage is * inconsistent. * 8 6017 (1781) Curve size p is invalid or its usage is inconsistent. */ switch (reason_code) { case 874: case 2158: case 6015: case 6017: return TRUE; } } return FALSE; } static CK_RV curve_supported(TEMPLATE *templ, uint8_t *curve_type, uint16_t *curve_bitlen) { CK_ATTRIBUTE *attr = NULL; unsigned int i; /* Check if curve supported */ if (!template_attribute_find(templ, CKA_ECDSA_PARAMS, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } for (i = 0; i < NUMEC; i++) { if ((attr->ulValueLen == der_ec_supported[i].data_size) && (memcmp(attr->pValue, der_ec_supported[i].data, attr->ulValueLen) == 0) && (der_ec_supported[i].curve_type == PRIME_CURVE || der_ec_supported[i].curve_type == BRAINPOOL_CURVE)) { *curve_type = der_ec_supported[i].curve_type; *curve_bitlen = der_ec_supported[i].len_bits; return CKR_OK; } } return CKR_CURVE_NOT_SUPPORTED; } uint16_t cca_ec_privkey_offset(CK_BYTE * tok) { uint8_t privkey_id = CCA_PRIVKEY_ID, privkey_rec; privkey_rec = ntohs(*(uint8_t *) & tok[CCA_EC_HEADER_SIZE]); if ((memcmp(&privkey_rec, &privkey_id, sizeof(uint8_t)) == 0)) { return CCA_EC_HEADER_SIZE; } TRACE_WARNING("+++++++++ Token key private section is CORRUPTED\n"); return CCA_EC_HEADER_SIZE; } uint16_t cca_ec_publkey_offset(CK_BYTE * tok) { uint16_t priv_offset, privSec_len; uint8_t publkey_id = CCA_PUBLKEY_ID, publkey_rec; priv_offset = cca_ec_privkey_offset(tok); privSec_len = ntohs(*(uint16_t *) & tok[priv_offset + CCA_SECTION_LEN_OFFSET]); publkey_rec = ntohs(*(uint8_t *) & tok[priv_offset + privSec_len]); if ((memcmp(&publkey_rec, &publkey_id, sizeof(uint8_t)) == 0)) { return (priv_offset + privSec_len); } TRACE_WARNING("++++++++ Token key public section is CORRUPTED\n"); return (priv_offset + privSec_len); } CK_RV token_create_ec_keypair(TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl, CK_ULONG tok_len, CK_BYTE * tok) { uint16_t pubkey_offset, qlen_offset, q_offset; CK_ULONG q_len; CK_BYTE q[CCATOK_EC_MAX_Q_LEN]; CK_RV rv; CK_ATTRIBUTE *attr = NULL; CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len; /* * The token includes the header section first, * the private key section in the middle, * and the public key section last. */ /* The pkcs#11v2.20: * CKA_ECDSA_PARAMS must be in public key's template when * generating key pair and added to private key template. * CKA_EC_POINT added to public key when key is generated. */ /* * Get Q data for public key. */ pubkey_offset = cca_ec_publkey_offset(tok); qlen_offset = pubkey_offset + CCA_EC_INTTOK_PUBKEY_Q_LEN_OFFSET; q_len = *(uint16_t *) & tok[qlen_offset]; q_len = ntohs(q_len); if (q_len > CCATOK_EC_MAX_Q_LEN) { TRACE_ERROR("Not enough room to return q. (Got %d, need %ld)\n", CCATOK_EC_MAX_Q_LEN, q_len); return CKR_FUNCTION_FAILED; } q_offset = pubkey_offset + CCA_EC_INTTOK_PUBKEY_Q_OFFSET; memcpy(q, &tok[q_offset], (size_t) q_len); rv = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, q, q_len); if (rv != CKR_OK) { TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); return rv; } if ((rv = build_update_attribute(publ_tmpl, CKA_EC_POINT, ecpoint, ecpoint_len))) { TRACE_DEVEL("build_update_attribute for q failed rv=0x%lx\n", rv); free(ecpoint); return rv; } free(ecpoint); /* Add ec params to private key */ if (!template_attribute_find(publ_tmpl, CKA_ECDSA_PARAMS, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } if ((rv = build_update_attribute(priv_tmpl, CKA_ECDSA_PARAMS, attr->pValue, attr->ulValueLen))) { TRACE_DEVEL("build_update_attribute for der data failed " "rv=0x%lx\n", rv); return rv; } /* * Save the CKA_IBM_OPAQUE for both keys. */ if ((rv = build_update_attribute(publ_tmpl, CKA_IBM_OPAQUE, tok, tok_len))) { TRACE_DEVEL("build_update_attribute for tok failed rv=0x%lx\n", rv); return rv; } if ((rv = build_update_attribute(priv_tmpl, CKA_IBM_OPAQUE, tok, tok_len))) { TRACE_DEVEL("build_update_attribute for tok failed rv=0x%lx\n", rv); return rv; } return CKR_OK; } CK_RV token_specific_ec_generate_keypair(STDLL_TokData_t * tokdata, TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl) { long return_code, reason_code, rule_array_count, exit_data_len = 0; unsigned char *exit_data = NULL; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long key_value_structure_length, private_key_name_length, key_token_length; unsigned char key_value_structure[CCA_EC_KEY_VALUE_STRUCT_SIZE] = { 0, }; unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; long regeneration_data_length, generated_key_token_length; unsigned char regeneration_data[CCA_REGENERATION_DATA_SIZE] = { 0, }; unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; unsigned char generated_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; CK_RV rv; long param1 = 0; unsigned char *param2 = NULL; uint8_t curve_type; uint16_t curve_bitlen; UNUSED(tokdata); rv = curve_supported(publ_tmpl, &curve_type, &curve_bitlen); if (rv != CKR_OK) { TRACE_ERROR("Curve not supported\n"); return rv; } /* * See CCA doc: page 94 for offset of data in key_value_structure */ memcpy(key_value_structure, &curve_type, sizeof(uint8_t)); memcpy(&key_value_structure[CCA_PKB_EC_LEN_OFFSET], &curve_bitlen, sizeof(uint16_t)); key_value_structure_length = CCA_EC_KEY_VALUE_STRUCT_SIZE; rule_array_count = 1; memcpy(rule_array, "ECC-PAIR", (size_t) (CCA_KEYWORD_SIZE)); private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (is_curve_error(return_code, reason_code)) return CKR_CURVE_NOT_SUPPORTED; return CKR_FUNCTION_FAILED; } rule_array_count = 1; memset(rule_array, 0, sizeof(rule_array)); memcpy(rule_array, "MASTER ", (size_t) CCA_KEYWORD_SIZE); generated_key_token_length = CCA_KEY_TOKEN_SIZE; regeneration_data_length = 0; dll_CSNDPKG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, ®eneration_data_length, regeneration_data, &key_token_length, key_token, transport_key_identifier, &generated_key_token_length, generated_key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKG (EC KEY GENERATE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (is_curve_error(return_code, reason_code)) return CKR_CURVE_NOT_SUPPORTED; return CKR_FUNCTION_FAILED; } TRACE_DEVEL("ECC secure key token generated. size: %ld\n", generated_key_token_length); rv = token_create_ec_keypair(publ_tmpl, priv_tmpl, generated_key_token_length, generated_key_token); if (rv != CKR_OK) { TRACE_DEVEL("token_create_ec_keypair failed. rv: %lu\n", rv); return rv; } return rv; } CK_RV token_specific_ec_sign(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len, OBJECT * key_obj) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long signature_bit_length; CK_ATTRIBUTE *attr; UNUSED(tokdata); UNUSED(sess); /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } /* CCA doc: page 113 */ rule_array_count = 1; memcpy(rule_array, "ECDSA ", CCA_KEYWORD_SIZE); dll_CSNDDSG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &(attr->ulValueLen), attr->pValue, (long *) &in_data_len, in_data, (long *) out_data_len, &signature_bit_length, out_data); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSG (EC SIGN) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (is_curve_error(return_code, reason_code)) return CKR_CURVE_NOT_SUPPORTED; return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { TRACE_WARNING("CSNDDSG (EC SIGN) succeeded, but" " returned reason:%ld\n", reason_code); } return CKR_OK; } CK_RV token_specific_ec_verify(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG out_data_len, OBJECT * key_obj) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_ATTRIBUTE *attr; UNUSED(tokdata); UNUSED(sess); /* Find the secure key token */ if (!template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } /* CCA doc: page 118 */ rule_array_count = 1; memcpy(rule_array, "ECDSA ", CCA_KEYWORD_SIZE); dll_CSNDDSV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *) &(attr->ulValueLen), attr->pValue, (long *) &in_data_len, in_data, (long *) &out_data_len, out_data); if (return_code == 4 && reason_code == 429) { return CKR_SIGNATURE_INVALID; } else if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDDSV (EC VERIFY) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (is_curve_error(return_code, reason_code)) return CKR_CURVE_NOT_SUPPORTED; return CKR_FUNCTION_FAILED; } else if (reason_code != 0) { TRACE_WARNING("CSNDDSV (EC VERIFY) succeeded, but" " returned reason:%ld\n", reason_code); } return CKR_OK; } CK_RV token_specific_sha_init(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * ctx, CK_MECHANISM * mech) { CK_ULONG hash_size; struct cca_sha_ctx *cca_ctx; UNUSED(tokdata); switch (mech->mechanism) { case CKM_SHA_1: hash_size = SHA1_HASH_SIZE; break; case CKM_SHA224: hash_size = SHA224_HASH_SIZE; break; case CKM_SHA256: hash_size = SHA256_HASH_SIZE; break; case CKM_SHA384: hash_size = SHA384_HASH_SIZE; break; case CKM_SHA512: hash_size = SHA512_HASH_SIZE; break; default: return CKR_MECHANISM_INVALID; } ctx->context = calloc(1, sizeof(struct cca_sha_ctx)); if (ctx->context == NULL) { TRACE_ERROR("malloc failed in sha digest init\n"); return CKR_HOST_MEMORY; } ctx->context_len = sizeof(struct cca_sha_ctx); cca_ctx = (struct cca_sha_ctx *) ctx->context; cca_ctx->chain_vector_len = CCA_CHAIN_VECTOR_LEN; cca_ctx->hash_len = hash_size; /* tail_len is already 0 */ return CKR_OK; } CK_RV token_specific_sha(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * ctx, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * out_data, CK_ULONG * out_data_len) { struct cca_sha_ctx *cca_ctx; long return_code, reason_code, rule_array_count = 2; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; UNUSED(tokdata); if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; if (!in_data || !out_data) return CKR_ARGUMENTS_BAD; cca_ctx = (struct cca_sha_ctx *) ctx->context; if (*out_data_len < (CK_ULONG)cca_ctx->hash_len) return CKR_BUFFER_TOO_SMALL; switch (ctx->mech.mechanism) { case CKM_SHA_1: memcpy(rule_array, "SHA-1 ONLY ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_ONLY; break; case CKM_SHA224: memcpy(rule_array, "SHA-224 ONLY ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_ONLY; break; case CKM_SHA256: memcpy(rule_array, "SHA-256 ONLY ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_ONLY; break; case CKM_SHA384: memcpy(rule_array, "SHA-384 ONLY ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_ONLY; break; case CKM_SHA512: memcpy(rule_array, "SHA-512 ONLY ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_ONLY; break; default: return CKR_MECHANISM_INVALID; } dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&in_data_len, in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBOWH failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(out_data, cca_ctx->hash, cca_ctx->hash_len); *out_data_len = cca_ctx->hash_len; /* ctx->context should get freed in digest_mgr_cleanup() */ return CKR_OK; } CK_RV token_specific_sha_update(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * ctx, CK_BYTE * in_data, CK_ULONG in_data_len) { struct cca_sha_ctx *cca_ctx; long return_code, reason_code, total, buffer_len, rule_array_count = 2; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; CK_RV rc = CKR_OK; unsigned char *buffer = NULL; int blocksz, blocksz_mask, use_buffer = 0; UNUSED(tokdata); if (!in_data) return CKR_ARGUMENTS_BAD; if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; switch (ctx->mech.mechanism) { case CKM_SHA_1: blocksz = SHA1_BLOCK_SIZE; blocksz_mask = SHA1_BLOCK_SIZE_MASK; break; case CKM_SHA224: blocksz = SHA224_BLOCK_SIZE; blocksz_mask = SHA224_BLOCK_SIZE_MASK; break; case CKM_SHA256: blocksz = SHA256_BLOCK_SIZE; blocksz_mask = SHA256_BLOCK_SIZE_MASK; break; case CKM_SHA384: blocksz = SHA384_BLOCK_SIZE; blocksz_mask = SHA384_BLOCK_SIZE_MASK; break; case CKM_SHA512: blocksz = SHA512_BLOCK_SIZE; blocksz_mask = SHA512_BLOCK_SIZE_MASK; break; default: return CKR_MECHANISM_INVALID; } cca_ctx = (struct cca_sha_ctx *) ctx->context; /* just send if input a multiple of block size and * cca_ctx-> tail is empty. */ if ((cca_ctx->tail_len == 0) && ((in_data_len & blocksz_mask) == 0)) goto send; /* at this point, in_data is not multiple of blocksize * and/or there is saved data from previous update still * needing to be processed */ /* get totals */ total = cca_ctx->tail_len + in_data_len; /* see if we have enough to fill a block */ if (total >= blocksz) { int remainder; remainder = total & blocksz_mask; buffer_len = total - remainder; /* allocate a buffer for sending... */ if (!(buffer = malloc(buffer_len))) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } memcpy(buffer, cca_ctx->tail, cca_ctx->tail_len); memcpy(buffer + cca_ctx->tail_len, in_data, in_data_len - remainder); use_buffer = 1; /* save remainder data for next time */ if (remainder) memcpy(cca_ctx->tail, in_data + (in_data_len - remainder), remainder); cca_ctx->tail_len = remainder; } else { /* not enough to fill a block, save off data for next round */ memcpy(cca_ctx->tail + cca_ctx->tail_len, in_data, in_data_len); cca_ctx->tail_len += in_data_len; return CKR_OK; } send: switch (ctx->mech.mechanism) { case CKM_SHA_1: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-1 FIRST ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array, "SHA-1 MIDDLE ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA224: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-224 FIRST ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array, "SHA-224 MIDDLE ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA256: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-256 FIRST ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array, "SHA-256 MIDDLE ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA384: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-384 FIRST ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array, "SHA-384 MIDDLE ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA512: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-512 FIRST ", CCA_KEYWORD_SIZE * 2); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array, "SHA-512 MIDDLE ", CCA_KEYWORD_SIZE * 2); } break; } dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, use_buffer ? &buffer_len : (long *) &in_data_len, use_buffer ? buffer : in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBOWH (SHA UPDATE) failed. return:%ld," " reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; } done: if (buffer) free(buffer); return rc; } CK_RV token_specific_sha_final(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * ctx, CK_BYTE * out_data, CK_ULONG * out_data_len) { struct cca_sha_ctx *cca_ctx; long return_code, reason_code, rule_array_count = 2; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; UNUSED(tokdata); if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; cca_ctx = (struct cca_sha_ctx *) ctx->context; if (*out_data_len < (CK_ULONG)cca_ctx->hash_len) { TRACE_ERROR("out buf too small for hash: %lu\n", *out_data_len); return CKR_BUFFER_TOO_SMALL; } switch (ctx->mech.mechanism) { case CKM_SHA_1: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-1 ONLY ", CCA_KEYWORD_SIZE * 2); } else { /* there's some extra data we need to hash to * complete the operation */ memcpy(rule_array, "SHA-1 LAST ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA224: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-224 ONLY ", CCA_KEYWORD_SIZE * 2); } else { /* there's some extra data we need to hash to * complete the operation */ memcpy(rule_array, "SHA-224 LAST ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA256: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-256 ONLY ", CCA_KEYWORD_SIZE * 2); } else { /* there's some extra data we need to hash to * complete the operation */ memcpy(rule_array, "SHA-256 LAST ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA384: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-384 ONLY ", CCA_KEYWORD_SIZE * 2); } else { /* there's some extra data we need to hash to * complete the operation */ memcpy(rule_array, "SHA-384 LAST ", CCA_KEYWORD_SIZE * 2); } break; case CKM_SHA512: if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array, "SHA-512 ONLY ", CCA_KEYWORD_SIZE * 2); } else { /* there's some extra data we need to hash to * complete the operation */ memcpy(rule_array, "SHA-512 LAST ", CCA_KEYWORD_SIZE * 2); } break; default: return CKR_MECHANISM_INVALID; } TRACE_DEBUG("tail_len: %lu, tail: %p, cvl: %lu, sl: %lu\n", cca_ctx->tail_len, (void *)cca_ctx->tail, cca_ctx->chain_vector_len, cca_ctx->hash_len); dll_CSNBOWH(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &cca_ctx->tail_len, cca_ctx->tail, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBOWH (SHA FINAL) failed. return:%ld," " reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(out_data, cca_ctx->hash, cca_ctx->hash_len); *out_data_len = cca_ctx->hash_len; /* ctx->context should get freed in digest_mgr_cleanup() */ return CKR_OK; } static long get_mac_len(CK_MECHANISM * mech) { switch (mech->mechanism) { case CKM_SHA_1_HMAC_GENERAL: case CKM_SHA224_HMAC_GENERAL: case CKM_SHA256_HMAC_GENERAL: case CKM_SHA384_HMAC_GENERAL: case CKM_SHA512_HMAC_GENERAL: return *(CK_ULONG *) (mech->pParameter); case CKM_SHA_1_HMAC: return SHA1_HASH_SIZE; case CKM_SHA224_HMAC: return SHA224_HASH_SIZE; case CKM_SHA256_HMAC: return SHA256_HASH_SIZE; case CKM_SHA384_HMAC: return SHA384_HASH_SIZE; case CKM_SHA512_HMAC: return SHA512_HASH_SIZE; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return -1; } } static CK_RV ccatok_hmac_init(SIGN_VERIFY_CONTEXT * ctx, CK_MECHANISM * mech, CK_OBJECT_HANDLE key) { struct cca_sha_ctx *cca_ctx; long maclen = -1; UNUSED(key); maclen = get_mac_len(mech); if (maclen < 0) return CKR_MECHANISM_INVALID; ctx->context = calloc(1, sizeof(struct cca_sha_ctx)); if (ctx->context == NULL) { TRACE_ERROR("malloc failed in sha digest init\n"); return CKR_HOST_MEMORY; } ctx->context_len = sizeof(struct cca_sha_ctx); cca_ctx = (struct cca_sha_ctx *) ctx->context; memset(cca_ctx, 0, sizeof(struct cca_sha_ctx)); cca_ctx->chain_vector_len = CCA_CHAIN_VECTOR_LEN; cca_ctx->hash_len = maclen; return CKR_OK; } CK_RV token_specific_hmac_sign_init(STDLL_TokData_t * tokdata, SESSION * sess, CK_MECHANISM * mech, CK_OBJECT_HANDLE key) { UNUSED(tokdata); return ccatok_hmac_init(&sess->sign_ctx, mech, key); } CK_RV token_specific_hmac_verify_init(STDLL_TokData_t * tokdata, SESSION * sess, CK_MECHANISM * mech, CK_OBJECT_HANDLE key) { UNUSED(tokdata); return ccatok_hmac_init(&sess->verify_ctx, mech, key); } CK_RV ccatok_hmac(STDLL_TokData_t * tokdata, SIGN_VERIFY_CONTEXT * ctx, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * signature, CK_ULONG * sig_len, CK_BBOOL sign) { struct cca_sha_ctx *cca_ctx; long keylen, return_code = 0, reason_code = 0, rule_array_count = 3; unsigned char rule_array[CCA_RULE_ARRAY_SIZE]; OBJECT *key = NULL; CK_ATTRIBUTE *attr = NULL; CK_RV rc = CKR_OK; if (!ctx || !ctx->context) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); return CKR_OPERATION_NOT_INITIALIZED; } cca_ctx = (struct cca_sha_ctx *) ctx->context; if (sign && !sig_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } keylen = attr->ulValueLen; if (template_attribute_find(key->template, CKA_IBM_OPAQUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } switch (ctx->mech.mechanism) { case CKM_SHA_1_HMAC_GENERAL: case CKM_SHA_1_HMAC: memcpy(rule_array, "HMAC SHA-1 ONLY ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA224_HMAC_GENERAL: case CKM_SHA224_HMAC: memcpy(rule_array, "HMAC SHA-224 ONLY ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA256_HMAC_GENERAL: case CKM_SHA256_HMAC: memcpy(rule_array, "HMAC SHA-256 ONLY ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA384_HMAC_GENERAL: case CKM_SHA384_HMAC: memcpy(rule_array, "HMAC SHA-384 ONLY ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA512_HMAC_GENERAL: case CKM_SHA512_HMAC: memcpy(rule_array, "HMAC SHA-512 ONLY ", 3 * CCA_KEYWORD_SIZE); break; default: TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); rc = CKR_MECHANISM_INVALID; goto done; } TRACE_INFO("HMAC key length is %ld\n", keylen); TRACE_INFO("The mac length is %ld\n", cca_ctx->hash_len); if (sign) { dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, (long int *)&in_data_len, in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC GENERATE) failed. " "return:%ld, reason:%ld\n", return_code, reason_code); *sig_len = 0; rc = CKR_FUNCTION_FAILED; goto done; } /* Copy the signature into the user supplied variable. * For hmac general mechs, only copy over the specified * number of bytes for the mac. */ memcpy(signature, cca_ctx->hash, cca_ctx->hash_len); *sig_len = cca_ctx->hash_len; } else { // verify dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, (long int *)&in_data_len, in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, signature); if (return_code == 4 && (reason_code == 429 || reason_code == 1)) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); rc = CKR_SIGNATURE_INVALID; goto done; } else if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMV (HMAC VERIFY) failed. return:%ld," " reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; goto done; } else if (reason_code != 0) { TRACE_WARNING("CSNBHMV (HMAC VERIFY) succeeded, but" " returned reason:%ld\n", reason_code); } } done: object_put(tokdata, key, TRUE); key = NULL; return rc; } CK_RV token_specific_hmac_sign(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * signature, CK_ULONG * sig_len) { return ccatok_hmac(tokdata, &sess->sign_ctx, in_data, in_data_len, signature, sig_len, TRUE); } CK_RV token_specific_hmac_verify(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BYTE * signature, CK_ULONG sig_len) { return ccatok_hmac(tokdata, &sess->verify_ctx, in_data, in_data_len, signature, &sig_len, FALSE); } CK_RV ccatok_hmac_update(STDLL_TokData_t * tokdata, SIGN_VERIFY_CONTEXT * ctx, CK_BYTE * in_data, CK_ULONG in_data_len, CK_BBOOL sign) { struct cca_sha_ctx *cca_ctx; long return_code, reason_code, total, buffer_len; long hsize, rule_array_count = 3; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; unsigned char *buffer = NULL; int blocksz, blocksz_mask, use_buffer = 0; OBJECT *key = NULL; CK_ATTRIBUTE *attr = NULL; CK_RV rc = CKR_OK; if (!ctx || !ctx->context) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); return CKR_OPERATION_NOT_INITIALIZED; } /* if zero input data, then just do nothing and return. * "final" should catch if this is case of hashing zero input. */ if (in_data_len == 0) return CKR_OK; rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } if (template_attribute_find(key->template, CKA_IBM_OPAQUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } switch (ctx->mech.mechanism) { case CKM_SHA_1_HMAC: case CKM_SHA_1_HMAC_GENERAL: case CKM_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA256_HMAC_GENERAL: blocksz = SHA1_BLOCK_SIZE; // set to 64 bytes blocksz_mask = SHA1_BLOCK_SIZE_MASK; // set to 63 break; case CKM_SHA384_HMAC: case CKM_SHA384_HMAC_GENERAL: case CKM_SHA512_HMAC: case CKM_SHA512_HMAC_GENERAL: blocksz = SHA512_BLOCK_SIZE; // set to 128 bytes blocksz_mask = SHA512_BLOCK_SIZE_MASK; // set to 127 break; default: rc = CKR_MECHANISM_INVALID; goto done; } cca_ctx = (struct cca_sha_ctx *) ctx->context; /* just send if input a multiple of block size and * cca_ctx-> tail is empty. */ if ((cca_ctx->tail_len == 0) && ((in_data_len & blocksz_mask) == 0)) goto send; /* at this point, in_data is not multiple of blocksize * and/or there is saved data from previous update still * needing to be processed */ /* get totals */ total = cca_ctx->tail_len + in_data_len; /* see if we have enough to fill a block */ if (total >= blocksz) { int remainder; remainder = total & blocksz_mask; // save left over buffer_len = total - remainder; /* allocate a buffer for sending... */ if (!(buffer = malloc(buffer_len))) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } /* copy data to send. * first get any data saved in tail from prior call, * then fill up remaining space in block with in_data */ memcpy(buffer, cca_ctx->tail, cca_ctx->tail_len); memcpy(buffer + cca_ctx->tail_len, in_data, in_data_len - remainder); use_buffer = 1; /* save remainder data for next time */ if (remainder) memcpy(cca_ctx->tail, in_data + (in_data_len - remainder), remainder); cca_ctx->tail_len = remainder; } else { /* not enough to fill a block, * so save off data for next round */ memcpy(cca_ctx->tail + cca_ctx->tail_len, in_data, in_data_len); cca_ctx->tail_len += in_data_len; rc = CKR_OK; goto done; } send: switch (ctx->mech.mechanism) { case CKM_SHA_1_HMAC: case CKM_SHA_1_HMAC_GENERAL: hsize = SHA1_HASH_SIZE; memcpy(rule_array, "HMAC SHA-1 ", CCA_KEYWORD_SIZE * 2); break; case CKM_SHA224_HMAC: case CKM_SHA224_HMAC_GENERAL: hsize = SHA224_HASH_SIZE; memcpy(rule_array, "HMAC SHA-224 ", CCA_KEYWORD_SIZE * 2); break; case CKM_SHA256_HMAC: case CKM_SHA256_HMAC_GENERAL: hsize = SHA256_HASH_SIZE; memcpy(rule_array, "HMAC SHA-256 ", CCA_KEYWORD_SIZE * 2); break; case CKM_SHA384_HMAC: case CKM_SHA384_HMAC_GENERAL: hsize = SHA384_HASH_SIZE; memcpy(rule_array, "HMAC SHA-384 ", CCA_KEYWORD_SIZE * 2); break; case CKM_SHA512_HMAC: case CKM_SHA512_HMAC_GENERAL: hsize = SHA512_HASH_SIZE; memcpy(rule_array, "HMAC SHA-512 ", CCA_KEYWORD_SIZE * 2); break; } if (cca_ctx->part == CCA_HASH_PART_FIRST) { memcpy(rule_array + (CCA_KEYWORD_SIZE * 2), "FIRST ", CCA_KEYWORD_SIZE); cca_ctx->part = CCA_HASH_PART_MIDDLE; } else { memcpy(rule_array + (CCA_KEYWORD_SIZE * 2), "MIDDLE ", CCA_KEYWORD_SIZE); } TRACE_INFO("CSNBHMG: key length is %lu\n", attr->ulValueLen); if (sign) { dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, use_buffer ? &buffer_len : (long int *) &in_data_len, use_buffer ? buffer : in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &hsize, cca_ctx->hash); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC SIGN UPDATE) failed. " "return:%ld, reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; } } else { // verify dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, use_buffer ? &buffer_len : (long int *) &in_data_len, use_buffer ? buffer : in_data, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &hsize, cca_ctx->hash); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC VERIFY UPDATE) failed. " "return:%ld, reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; } } done: if (buffer) free(buffer); object_put(tokdata, key, TRUE); key = NULL; return rc; } CK_RV token_specific_hmac_sign_update(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * in_data, CK_ULONG in_data_len) { return ccatok_hmac_update(tokdata, &sess->sign_ctx, in_data, in_data_len, TRUE); } CK_RV token_specific_hmac_verify_update(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * in_data, CK_ULONG in_data_len) { return ccatok_hmac_update(tokdata, &sess->verify_ctx, in_data, in_data_len, FALSE); } CK_RV ccatok_hmac_final(STDLL_TokData_t * tokdata, SIGN_VERIFY_CONTEXT * ctx, CK_BYTE * signature, CK_ULONG * sig_len, CK_BBOOL sign) { struct cca_sha_ctx *cca_ctx; long return_code, reason_code, rule_array_count = 3; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; OBJECT *key = NULL; CK_ATTRIBUTE *attr = NULL; CK_RV rc = CKR_OK; if (!ctx || !ctx->context) { TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED)); return CKR_OPERATION_NOT_INITIALIZED; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } if (template_attribute_find(key->template, CKA_IBM_OPAQUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } cca_ctx = (struct cca_sha_ctx *) ctx->context; switch (ctx->mech.mechanism) { case CKM_SHA_1_HMAC: case CKM_SHA_1_HMAC_GENERAL: memcpy(rule_array, "HMAC SHA-1 ", CCA_KEYWORD_SIZE * 2); break; case CKM_SHA224_HMAC: case CKM_SHA224_HMAC_GENERAL: memcpy(rule_array, "HMAC SHA-224 ", CCA_KEYWORD_SIZE * 2); break; case CKM_SHA256_HMAC: case CKM_SHA256_HMAC_GENERAL: memcpy(rule_array, "HMAC SHA-256 ", CCA_KEYWORD_SIZE * 2); break; case CKM_SHA384_HMAC: case CKM_SHA384_HMAC_GENERAL: memcpy(rule_array, "HMAC SHA-384 ", CCA_KEYWORD_SIZE * 2); break; case CKM_SHA512_HMAC: case CKM_SHA512_HMAC_GENERAL: memcpy(rule_array, "HMAC SHA-512 ", CCA_KEYWORD_SIZE * 2); break; default: rc = CKR_MECHANISM_INVALID; goto done; } if (cca_ctx->part == CCA_HASH_PART_FIRST) memcpy(rule_array + (CCA_KEYWORD_SIZE * 2), "ONLY ", CCA_KEYWORD_SIZE); else memcpy(rule_array + (CCA_KEYWORD_SIZE * 2), "LAST ", CCA_KEYWORD_SIZE); TRACE_INFO("CSNBHMG: key length is %lu\n", attr->ulValueLen); TRACE_INFO("The mac length is %ld\n", cca_ctx->hash_len); if (sign) { dll_CSNBHMG(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, &cca_ctx->tail_len, cca_ctx->tail, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, cca_ctx->hash); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMG (HMAC SIGN FINAL) failed. " "return:%ld, reason:%ld\n", return_code, reason_code); *sig_len = 0; rc = CKR_FUNCTION_FAILED; goto done; } /* Copy the signature into the user supplied variable. * For hmac general mechs, only copy over the specified * number of bytes for the mac. */ memcpy(signature, cca_ctx->hash, cca_ctx->hash_len); *sig_len = cca_ctx->hash_len; } else { // verify dll_CSNBHMV(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, &cca_ctx->tail_len, cca_ctx->tail, &cca_ctx->chain_vector_len, cca_ctx->chain_vector, &cca_ctx->hash_len, signature); if (return_code == 4 && (reason_code == 429 || reason_code == 1)) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); rc = CKR_SIGNATURE_INVALID; goto done; } else if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBHMV (HMAC VERIFY) failed. return:%ld," " reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; goto done; } else if (reason_code != 0) { TRACE_WARNING("CSNBHMV (HMAC VERIFY) succeeded, but" " returned reason:%ld\n", reason_code); } } done: object_put(tokdata, key, TRUE); key = NULL; return rc; } CK_RV token_specific_hmac_sign_final(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * signature, CK_ULONG * sig_len) { return ccatok_hmac_final(tokdata, &sess->sign_ctx, signature, sig_len, TRUE); } CK_RV token_specific_hmac_verify_final(STDLL_TokData_t * tokdata, SESSION * sess, CK_BYTE * signature, CK_ULONG sig_len) { return ccatok_hmac_final(tokdata, &sess->verify_ctx, signature, &sig_len, FALSE); } static CK_RV rsa_import_privkey_crt(TEMPLATE * priv_tmpl) { long return_code, reason_code, rule_array_count, total = 0; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long offset, key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; long private_key_name_length, key_token_length, target_key_token_length; unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char target_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; uint16_t size_of_e; uint16_t mod_bits, mod_bytes, bytes; CK_ATTRIBUTE *opaque_key = NULL, *pub_exp = NULL, *mod = NULL, *p_prime = NULL, *q_prime = NULL, *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL, *priv_exp = NULL; CK_RV rc; /* Look for parameters to set key in the CRT format */ if (!template_attribute_find(priv_tmpl, CKA_PRIME_1, &p_prime)) { TRACE_ERROR("CKA_PRIME_1 attribute missing for CRT.\n"); return CKR_TEMPLATE_INCOMPLETE; } total += p_prime->ulValueLen; if (!template_attribute_find(priv_tmpl, CKA_PRIME_2, &q_prime)) { TRACE_ERROR("CKA_PRIME_2 attribute missing for CRT.\n"); return CKR_TEMPLATE_INCOMPLETE; } total += q_prime->ulValueLen; if (!template_attribute_find(priv_tmpl, CKA_EXPONENT_1, &dmp1)) { TRACE_ERROR("CKA_EXPONENT_1 attribute missing for CRT.\n"); return CKR_TEMPLATE_INCOMPLETE; } total += dmp1->ulValueLen; if (!template_attribute_find(priv_tmpl, CKA_EXPONENT_2, &dmq1)) { TRACE_ERROR("CKA_EXPONENT_2 attribute missing for CRT.\n"); return CKR_TEMPLATE_INCOMPLETE; } total += dmq1->ulValueLen; if (!template_attribute_find(priv_tmpl, CKA_COEFFICIENT, &iqmp)) { TRACE_ERROR("CKA_COEFFICIENT attribute missing for CRT.\n"); return CKR_TEMPLATE_INCOMPLETE; } total += iqmp->ulValueLen; if (!template_attribute_find(priv_tmpl, CKA_PUBLIC_EXPONENT, &pub_exp)) { TRACE_ERROR("CKA_PUBLIC_EXPONENT attribute missing for CRT.\n"); return CKR_TEMPLATE_INCOMPLETE; } total += pub_exp->ulValueLen; if (!template_attribute_find(priv_tmpl, CKA_MODULUS, &mod)) { TRACE_ERROR("CKA_MODULUS attribute missing for CRT.\n"); return CKR_TEMPLATE_INCOMPLETE; } total += mod->ulValueLen; /* check total length does not exceed key_value_structure_length */ if ((total + 18) > key_value_structure_length) { TRACE_ERROR("total length of key exceeds CCA_KEY_VALUE_STRUCT_SIZE.\n"); return CKR_KEY_SIZE_RANGE; } /* Build key token for RSA-PRIV format. * Fields according to Table 9. * PKA_Key_Token_Build key-values-structure */ memset(key_value_structure, 0, key_value_structure_length); /* Field #1 - Length of modulus in bits */ mod_bits = htons(mod->ulValueLen * 8); memcpy(&key_value_structure[0], &mod_bits, sizeof(uint16_t)); /* Field #2 - Length of modulus field in bytes */ mod_bytes = htons(mod->ulValueLen); memcpy(&key_value_structure[2], &mod_bytes, sizeof(uint16_t)); /* Field #3 - Length of public exponent field in bytes */ size_of_e = htons(pub_exp->ulValueLen); memcpy(&key_value_structure[4], &size_of_e, sizeof(uint16_t)); /* Field #4 - Reserved, binary zero, two bytes */ /* Field #5 - Length of prime P */ bytes = htons(p_prime->ulValueLen); memcpy(&key_value_structure[8], &bytes, sizeof(uint16_t)); /* Field #6 - Length of prime Q */ bytes = htons(q_prime->ulValueLen); memcpy(&key_value_structure[10], &bytes, sizeof(uint16_t)); /* Field #7 - Length of dp in bytes */ bytes = htons(dmp1->ulValueLen); memcpy(&key_value_structure[12], &bytes, sizeof(uint16_t)); /* Field #8 - Length of dq in bytes */ bytes = htons(dmq1->ulValueLen); memcpy(&key_value_structure[14], &bytes, sizeof(uint16_t)); /* Field #9 - Length of U in bytes */ bytes = htons(iqmp->ulValueLen); memcpy(&key_value_structure[16], &bytes, sizeof(uint16_t)); /* Field #10 - Modulus */ memcpy(&key_value_structure[18], mod->pValue, mod_bytes); offset = 18 + mod_bytes; /* Field #11 - Public Exponent */ memcpy(&key_value_structure[offset], pub_exp->pValue, pub_exp->ulValueLen); offset += pub_exp->ulValueLen; /* Field #12 - Prime numer, p */ memcpy(&key_value_structure[offset], p_prime->pValue, p_prime->ulValueLen); offset += p_prime->ulValueLen; /* Field #13 - Prime numer, q */ memcpy(&key_value_structure[offset], q_prime->pValue, q_prime->ulValueLen); offset += q_prime->ulValueLen; /* Field #14 - dp = dmod(p-1) */ memcpy(&key_value_structure[offset], dmp1->pValue, dmp1->ulValueLen); offset += dmp1->ulValueLen; /* Field #15 - dq = dmod(q-1) */ memcpy(&key_value_structure[offset], dmq1->pValue, dmq1->ulValueLen); offset += dmq1->ulValueLen; /* Field #16 - U = (q^-1)mod(p) */ memcpy(&key_value_structure[offset], iqmp->pValue, iqmp->ulValueLen); /* Now build a key token with the imported public key */ rule_array_count = 2; memcpy(rule_array, "RSA-AESCKEY-MGMT", (size_t) (CCA_KEYWORD_SIZE * 2)); private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, &key_token_length, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD RSA CRT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; goto err; } /* Now import the PKA key token */ rule_array_count = 0; /* memcpy(rule_array, " ", (size_t)(CCA_KEYWORD_SIZE * 1)); */ target_key_token_length = CCA_KEY_TOKEN_SIZE; key_token_length = CCA_KEY_TOKEN_SIZE; dll_CSNDPKI(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_token_length, key_token, transport_key_identifier, &target_key_token_length, target_key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKI (RSA KEY TOKEN IMPORT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); rc = CKR_FUNCTION_FAILED; goto err; } /* Add the key object to the template */ if ((rc = build_attribute(CKA_IBM_OPAQUE, target_key_token, target_key_token_length, &opaque_key))) { TRACE_DEVEL("build_attribute failed\n"); goto err; } rc = template_update_attribute(priv_tmpl, opaque_key); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); goto err; } OPENSSL_cleanse(p_prime->pValue, p_prime->ulValueLen); OPENSSL_cleanse(q_prime->pValue, q_prime->ulValueLen); OPENSSL_cleanse(dmp1->pValue, dmp1->ulValueLen); OPENSSL_cleanse(dmq1->pValue, dmq1->ulValueLen); OPENSSL_cleanse(iqmp->pValue, iqmp->ulValueLen); if (template_attribute_find(priv_tmpl, CKA_PRIVATE_EXPONENT, &priv_exp)) { OPENSSL_cleanse(priv_exp->pValue, priv_exp->ulValueLen); } rc =CKR_OK; err: OPENSSL_cleanse(key_value_structure, sizeof(key_value_structure)); return rc; } static CK_RV rsa_import_pubkey(TEMPLATE * publ_tmpl) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; long private_key_name_length, key_token_length; unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; uint16_t size_of_e; uint16_t mod_bits, mod_bytes; CK_ATTRIBUTE *opaque_key = NULL, *pub_exp = NULL; CK_ATTRIBUTE *pub_mod = NULL, *attr = NULL; CK_RV rc; /* check that modulus and public exponent are available */ if (!template_attribute_find(publ_tmpl, CKA_PUBLIC_EXPONENT, &pub_exp)) { TRACE_ERROR("CKA_PUBLIC_EXPONENT attribute missing.\n"); return CKR_TEMPLATE_INCOMPLETE; } if (!template_attribute_find(publ_tmpl, CKA_MODULUS, &pub_mod)) { TRACE_ERROR("CKA_MODULUS attribute missing.\n"); return CKR_TEMPLATE_INCOMPLETE; } if (!template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr)) { TRACE_ERROR("CKA_MODULUS_BITS attribute missing.\n"); return CKR_TEMPLATE_INCOMPLETE; } /* check total length does not exceed key_value_structure_length */ if ((pub_mod->ulValueLen + 8) > (CK_ULONG)key_value_structure_length) { TRACE_ERROR("total length of key exceeds CCA_KEY_VALUE_STRUCT_SIZE.\n"); return CKR_KEY_SIZE_RANGE; } /* In case the application hasn't filled it */ if (*(CK_ULONG *) attr->pValue == 0) mod_bits = htons(pub_mod->ulValueLen * 8); else mod_bits = htons(*(CK_ULONG *) attr->pValue); /* Build key token for RSA-PUBL format */ memset(key_value_structure, 0, key_value_structure_length); /* Fields according to Table 9. * PKA_Key_Token_Build key-values-structure */ /* Field #1 - Length of modulus in bits */ memcpy(&key_value_structure[0], &mod_bits, sizeof(uint16_t)); /* Field #2 - Length of modulus field in bytes */ mod_bytes = htons(pub_mod->ulValueLen); memcpy(&key_value_structure[2], &mod_bytes, sizeof(uint16_t)); /* Field #3 - Length of public exponent field in bytes */ size_of_e = htons((uint16_t) pub_exp->ulValueLen); memcpy(&key_value_structure[4], &size_of_e, sizeof(uint16_t)); /* Field #4 - private key exponent length; skip */ /* Field #5 - Modulus */ memcpy(&key_value_structure[8], pub_mod->pValue, (size_t) pub_mod->ulValueLen); /* Field #6 - Public exponent. Its offset depends on modulus size */ memcpy(&key_value_structure[8 + mod_bytes], pub_exp->pValue, (size_t) pub_exp->ulValueLen); /* Field #7 - Private exponent. Skip */ rule_array_count = 1; memcpy(rule_array, "RSA-PUBL", (size_t) (CCA_KEYWORD_SIZE * 1)); private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; // Create a key token for the public key. // Public keys do not need to be wrapped, so just call PKB. dll_CSNDPKB(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, &key_token_length, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (RSA KEY TOKEN BUILD RSA-PUBL) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } // Add the key object to the template. if ((rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_length, &opaque_key))) { TRACE_DEVEL("build_attribute failed\n"); return rc; } rc = template_update_attribute(publ_tmpl, opaque_key); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute failed\n"); return rc; } return CKR_OK; } static CK_RV import_symmetric_key(OBJECT * object, CK_ULONG keytype) { CK_RV rc; long return_code, reason_code, rule_array_count; unsigned char target_key_id[CCA_KEY_ID_SIZE] = { 0 }; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; CK_ATTRIBUTE *opaque_key = NULL; CK_ATTRIBUTE *attr = NULL; rc = template_attribute_find(object->template, CKA_VALUE, &attr); if (rc == FALSE) { TRACE_ERROR("Incomplete key template\n"); return CKR_TEMPLATE_INCOMPLETE; } switch (keytype) { case CKK_AES: memcpy(rule_array, "AES ", CCA_KEYWORD_SIZE); break; case CKK_DES: case CKK_DES3: memcpy(rule_array, "DES ", CCA_KEYWORD_SIZE); break; default: return CKR_KEY_FUNCTION_NOT_PERMITTED; } rule_array_count = 1; dll_CSNBCKM(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long int *)&attr->ulValueLen, attr->pValue, target_key_id); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBCKM failed. return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } /* Add the key object to the template */ if ((rc = build_attribute(CKA_IBM_OPAQUE, target_key_id, CCA_KEY_ID_SIZE, &opaque_key))) { TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } rc = template_update_attribute(object->template, opaque_key); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } /* zero clear key value */ OPENSSL_cleanse(attr->pValue, attr->ulValueLen); return CKR_OK; } static CK_RV import_generic_secret_key(OBJECT * object) { CK_RV rc; long return_code, reason_code, rule_array_count; unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0 }; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; long key_name_len = 0, clr_key_len = 0; long user_data_len = 0, key_part_len = 0; long token_data_len = 0, verb_data_len = 0; long key_token_len = sizeof(key_token); CK_ATTRIBUTE *opaque_key = NULL; CK_ATTRIBUTE *attr = NULL; CK_ULONG keylen; rc = template_attribute_find(object->template, CKA_VALUE, &attr); if (rc == FALSE) { TRACE_ERROR("Incomplete Generic Secret (HMAC) key template\n"); return CKR_TEMPLATE_INCOMPLETE; } keylen = attr->ulValueLen; /* key len needs to be 80-2048 bits */ if (8 * keylen < 80 || 8 * keylen > 2048) { TRACE_ERROR("HMAC key size of %lu bits not within" " CCA required range of 80-2048 bits\n", 8 * keylen); return CKR_KEY_SIZE_RANGE; } memcpy(rule_array, "INTERNALNO-KEY HMAC MAC GENERATE", 5 * CCA_KEYWORD_SIZE); rule_array_count = 5; dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &clr_key_len, NULL, &key_name_len, NULL, &user_data_len, NULL, &token_data_len, NULL, &verb_data_len, NULL, &key_token_len, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (HMAC KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "HMAC FIRST MIN1PART", 3 * CCA_KEYWORD_SIZE); rule_array_count = 3; key_part_len = keylen * 8; key_token_len = sizeof(key_token); dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_part_len, attr->pValue, &key_token_len, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (HMAC KEY IMPORT FIRST) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } memcpy(rule_array, "HMAC COMPLETE", 2 * CCA_KEYWORD_SIZE); rule_array_count = 2; key_part_len = 0; key_token_len = sizeof(key_token); dll_CSNBKPI2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_part_len, NULL, &key_token_len, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKPI2 (HMAC KEY IMPORT COMPLETE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } /* Add the key object to the template */ if ((rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_len, &opaque_key))) { TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } rc = template_update_attribute(object->template, opaque_key); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } /* zero clear key value */ OPENSSL_cleanse(attr->pValue, attr->ulValueLen); return CKR_OK; } static CK_RV build_private_EC_key_value_structure(CK_BYTE *privkey, CK_ULONG privlen, CK_BYTE *pubkey, CK_ULONG publen, uint8_t curve_type, uint16_t curve_bitlen, unsigned char *key_value_structure, long *key_value_structure_length) { ECC_PAIR ecc_pair; ecc_pair.curve_type = curve_type; ecc_pair.reserved = 0x00; ecc_pair.p_bitlen = curve_bitlen; ecc_pair.d_length = privlen; /* Adjust public key if necessary: there may be an indication if the public * key is compressed, uncompressed, or hybrid. */ if (publen == 2 * privlen + 1) { if (pubkey[0] == POINT_CONVERSION_UNCOMPRESSED || pubkey[0] == POINT_CONVERSION_HYBRID || pubkey[0] == POINT_CONVERSION_HYBRID+1) { /* uncompressed or hybrid EC public key */ ecc_pair.q_length = publen; memcpy(key_value_structure, &ecc_pair, sizeof(ECC_PAIR)); memcpy(key_value_structure + sizeof(ECC_PAIR), privkey, privlen); memcpy(key_value_structure + sizeof(ECC_PAIR) + privlen, pubkey, publen); *key_value_structure_length = sizeof(ECC_PAIR) + privlen + publen; } else { TRACE_ERROR("Unsupported public key format\n"); return CKR_TEMPLATE_INCONSISTENT; } } else if (publen == 2 * privlen) { /* uncompressed or hybrid EC public key without leading indication */ ecc_pair.q_length = publen + 1; memcpy(key_value_structure, &ecc_pair, sizeof(ECC_PAIR)); memcpy(key_value_structure + sizeof(ECC_PAIR), privkey, privlen); memset(key_value_structure + sizeof(ECC_PAIR) + privlen, POINT_CONVERSION_UNCOMPRESSED, 1); memcpy(key_value_structure + sizeof(ECC_PAIR) + privlen + 1, pubkey, publen); *key_value_structure_length = sizeof(ECC_PAIR) + privlen + 1 + publen; } else { TRACE_ERROR("Unsupported private/public key length (%ld,%ld)\n",privlen,publen); TRACE_ERROR("Compressed public keys are not supported by this token.\n"); return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } static unsigned int bitlen2bytelen(uint16_t bitlen) { if (bitlen != CURVE521) return bitlen / 8; return bitlen / 8 + 1; } static CK_RV build_public_EC_key_value_structure(CK_BYTE *pubkey, CK_ULONG publen, uint8_t curve_type, uint16_t curve_bitlen, unsigned char *key_value_structure, long *key_value_structure_length) { ECC_PUBL ecc_publ; ecc_publ.curve_type = curve_type; ecc_publ.reserved = 0x00; ecc_publ.p_bitlen = curve_bitlen; if (publen == 2 * bitlen2bytelen(curve_bitlen) + 1) { if (pubkey[0] == POINT_CONVERSION_UNCOMPRESSED || pubkey[0] == POINT_CONVERSION_HYBRID || pubkey[0] == POINT_CONVERSION_HYBRID+1) { /* uncompressed or hybrid EC public key */ ecc_publ.q_length = publen; memcpy(key_value_structure, &ecc_publ, sizeof(ECC_PUBL)); memcpy(key_value_structure + sizeof(ECC_PUBL), pubkey, publen); *key_value_structure_length = sizeof(ECC_PUBL) + publen; } else { TRACE_ERROR("Unsupported public key format\n"); return CKR_TEMPLATE_INCONSISTENT; } } else if (publen == 2 * bitlen2bytelen(curve_bitlen)) { /* uncompressed or hybrid EC public key without leading 0x04 */ ecc_publ.q_length = publen + 1; memcpy(key_value_structure, &ecc_publ, sizeof(ECC_PUBL)); memset(key_value_structure + sizeof(ECC_PUBL), POINT_CONVERSION_UNCOMPRESSED, 1); memcpy(key_value_structure + sizeof(ECC_PUBL) + 1, pubkey, publen); *key_value_structure_length = sizeof(ECC_PUBL) + publen + 1; } else { TRACE_ERROR("Unsupported public key length %ld\n",publen); TRACE_ERROR("Compressed public keys are not supported by this token.\n"); return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } static CK_RV ec_import_privkey(TEMPLATE *priv_templ) { long private_key_name_length, key_token_length, target_key_token_length; long return_code, reason_code, rule_array_count, exit_data_len = 0; long key_value_structure_length, param1=0; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; unsigned char target_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char *exit_data = NULL; unsigned char *param2=NULL; CK_BYTE *privkey = NULL, *pubkey = NULL; CK_ATTRIBUTE *attr = NULL, *opaque_key; CK_ULONG privlen = 0, publen = 0; CK_RV rc; uint8_t curve_type; uint16_t curve_bitlen; CK_ULONG field_len; /* Check if curve supported and determine curve type and bitlen */ rc = curve_supported(priv_templ, &curve_type, &curve_bitlen); if (rc != CKR_OK) { TRACE_ERROR("Curve not supported by this token.\n"); return rc; } /* Find private key data in template */ rc = template_attribute_find(priv_templ, CKA_VALUE, &attr); if (rc == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } privlen = attr->ulValueLen; privkey = attr->pValue; /* Find public key data as BER encoded OCTET STRING in template */ rc = template_attribute_find(priv_templ, CKA_EC_POINT, &attr); if (rc == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } rc = ber_decode_OCTET_STRING(attr->pValue, &pubkey, &publen, &field_len); if (rc != CKR_OK || attr->ulValueLen != field_len) { TRACE_DEVEL("ber decoding of public key failed\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } /* Build key_value_structure */ memset(key_value_structure, 0, CCA_KEY_VALUE_STRUCT_SIZE); rc = build_private_EC_key_value_structure(privkey, privlen, pubkey, publen, curve_type, curve_bitlen, (unsigned char *)&key_value_structure, &key_value_structure_length); if (rc != CKR_OK) return rc; /* Build key token */ rule_array_count = 1; memcpy(rule_array, "ECC-PAIR", (size_t)(CCA_KEYWORD_SIZE)); private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (is_curve_error(return_code, reason_code)) return CKR_CURVE_NOT_SUPPORTED; return CKR_FUNCTION_FAILED; } /* Now import the PKA key token */ rule_array_count = 1; memcpy(rule_array, "ECC ", (size_t)(CCA_KEYWORD_SIZE)); key_token_length = CCA_KEY_TOKEN_SIZE; target_key_token_length = CCA_KEY_TOKEN_SIZE; dll_CSNDPKI(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &key_token_length, key_token, transport_key_identifier, &target_key_token_length, target_key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKI (EC KEY TOKEN IMPORT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (is_curve_error(return_code, reason_code)) return CKR_CURVE_NOT_SUPPORTED; return CKR_FUNCTION_FAILED; } /* Add key token to template as CKA_IBM_OPAQUE */ if ((rc = build_attribute(CKA_IBM_OPAQUE, target_key_token, target_key_token_length, &opaque_key))) { TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } rc = template_update_attribute(priv_templ, opaque_key); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } /* zero clear key values */ OPENSSL_cleanse(privkey, privlen); return CKR_OK; } static CK_RV ec_import_pubkey(TEMPLATE *pub_templ) { CK_RV rc; long return_code, reason_code, rule_array_count, exit_data_len = 0; long private_key_name_length, key_token_length; unsigned char *exit_data = NULL; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; long key_value_structure_length; unsigned char key_value_structure[CCA_KEY_VALUE_STRUCT_SIZE] = { 0, }; unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; CK_ATTRIBUTE *opaque_key; long param1=0; unsigned char *param2=NULL; uint8_t curve_type; uint16_t curve_bitlen; CK_BYTE *pubkey = NULL; CK_ULONG publen = 0; CK_ATTRIBUTE *attr = NULL; CK_ULONG field_len; /* Check if curve supported and determine curve type and bitlen */ rc = curve_supported(pub_templ, &curve_type, &curve_bitlen); if (rc != CKR_OK) { TRACE_ERROR("Curve not supported by this token.\n"); return rc; } /* Find public key data as BER encoded OCTET STRING in template */ rc = template_attribute_find(pub_templ, CKA_EC_POINT, &attr); if (rc == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } rc = ber_decode_OCTET_STRING(attr->pValue, &pubkey, &publen, &field_len); if (rc != CKR_OK || attr->ulValueLen != field_len) { TRACE_DEVEL("ber decoding of public key failed\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } /* Build key_value_structure */ memset(key_value_structure, 0, CCA_KEY_VALUE_STRUCT_SIZE); rc = build_public_EC_key_value_structure(pubkey, publen, curve_type, curve_bitlen, (unsigned char *)&key_value_structure, &key_value_structure_length); if (rc != CKR_OK) return rc; /* Build public key token */ rule_array_count = 1; memcpy(rule_array, "ECC-PUBL", (size_t)(CCA_KEYWORD_SIZE)); private_key_name_length = 0; key_token_length = CCA_KEY_TOKEN_SIZE; key_value_structure_length = CCA_KEY_VALUE_STRUCT_SIZE; dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_value_structure_length, key_value_structure, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDPKB (EC KEY TOKEN BUILD) failed. return:%ld," " reason:%ld\n", return_code, reason_code); if (is_curve_error(return_code, reason_code)) return CKR_CURVE_NOT_SUPPORTED; return CKR_FUNCTION_FAILED; } /* Public keys do not need to be wrapped, so just add public key token to template as CKA_IBM_OPAQUE */ if ((rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_length, &opaque_key))) { TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } rc = template_update_attribute(pub_templ, opaque_key); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } return CKR_OK; } CK_RV token_specific_object_add(STDLL_TokData_t *tokdata, SESSION *sess, OBJECT *object) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE keytype; CK_OBJECT_CLASS keyclass; UNUSED(tokdata); UNUSED(sess); if (!object) { TRACE_ERROR("Invalid argument\n"); return CKR_FUNCTION_FAILED; } rc = template_attribute_find(object->template, CKA_KEY_TYPE, &attr); if (rc == FALSE) { // not a key, so nothing to do. Just return. TRACE_DEVEL("object not a key, no need to import.\n"); return CKR_OK; } keytype = *(CK_KEY_TYPE *)attr->pValue; switch (keytype) { case CKK_RSA: rc = template_attribute_find(object->template, CKA_CLASS, &attr); if (rc == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } keyclass = *(CK_OBJECT_CLASS *)attr->pValue; switch(keyclass) { case CKO_PUBLIC_KEY: // do import public key and create opaque object rc = rsa_import_pubkey(object->template); break; case CKO_PRIVATE_KEY: // do import keypair and create opaque object rc = rsa_import_privkey_crt(object->template); break; default: TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } if (rc != CKR_OK) { TRACE_DEVEL("rsa import failed\n"); return rc; } break; case CKK_AES: case CKK_DES: case CKK_DES3: rc = import_symmetric_key(object, keytype); if (rc != CKR_OK) { TRACE_DEVEL("Symmetric key import failed, rc=0x%lx\n", rc); return rc; } TRACE_INFO("symmetric key with len=%ld successful imported\n", attr->ulValueLen); break; case CKK_GENERIC_SECRET: rc = import_generic_secret_key(object); if (rc != CKR_OK) { TRACE_DEVEL("Generic Secret (HMAC) key import failed " " with rc=0x%lx\n", rc); return rc; } TRACE_INFO("Generic Secret (HMAC) key with len=%ld successfully" " imported\n", attr->ulValueLen); break; case CKK_EC: rc = template_attribute_find(object->template, CKA_CLASS, &attr); if (rc == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } keyclass = *(CK_OBJECT_CLASS *)attr->pValue; switch(keyclass) { case CKO_PUBLIC_KEY: // do import public key and create opaque object rc = ec_import_pubkey(object->template); break; case CKO_PRIVATE_KEY: // do import keypair and create opaque object rc = ec_import_privkey(object->template); break; default: TRACE_ERROR("%s\n", ock_err(ERR_KEY_TYPE_INCONSISTENT)); return CKR_KEY_TYPE_INCONSISTENT; } if (rc != CKR_OK) { TRACE_DEVEL("ec import failed\n"); return rc; } break; default: /* unknown/unsupported key type */ TRACE_ERROR("Unknown/unsupported key type 0x%lx\n", keytype); return CKR_KEY_FUNCTION_NOT_PERMITTED; } return CKR_OK; } CK_RV token_specific_generic_secret_key_gen(STDLL_TokData_t * tokdata, TEMPLATE * template) { CK_RV rc; long return_code, reason_code, rule_array_count; long zero_length = 0; long key_name_length = 0, clear_key_length = 0, user_data_length = 0; CK_ATTRIBUTE *opaque_key = NULL; CK_ATTRIBUTE *attr = NULL; CK_ULONG keylength = 0; unsigned char key_type1[8] = { 0 }; unsigned char key_type2[8] = { 0 }; unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0 }; long key_token_length = sizeof(key_token); unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; UNUSED(tokdata); rc = template_attribute_find(template, CKA_VALUE_LEN, &attr); if (rc == FALSE) { TRACE_ERROR("Incomplete Generic Secret (HMAC) key template\n"); return CKR_TEMPLATE_INCOMPLETE; } keylength = *(CK_ULONG *) attr->pValue; /* HMAC key length needs to be 80-2048 bits */ if (((8 * keylength) < 80) || ((8 * keylength) > 2048)) { TRACE_ERROR("HMAC key size of %lu bits not within CCA required " "range of 80-2048 bits\n", 8 * keylength); return CKR_KEY_SIZE_RANGE; } rule_array_count = 4; memcpy(rule_array, "INTERNALHMAC MAC GENERATE", 4 * CCA_KEYWORD_SIZE); dll_CSNBKTB2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, &clear_key_length, NULL, &key_name_length, NULL, &user_data_length, NULL, &zero_length, NULL, &zero_length, NULL, &key_token_length, key_token); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKTB2 (HMAC KEY TOKEN BUILD) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } /** generate the hmac key here **/ /* reset some values usually previously */ rule_array_count = 2; memset(rule_array, 0, sizeof(rule_array)); key_token_length = sizeof(key_token); /* create rule_array with 2 keywords */ memcpy(rule_array, "HMAC OP ", 2 * CCA_KEYWORD_SIZE); /* ask to create the hmac key with application * specified key length in bits */ clear_key_length = keylength * 8; memcpy(key_type1, "TOKEN ", CCA_KEYWORD_SIZE); /* for only one copy of key generated, specify 8 spaces in * key_type2 per CCA basic services guide */ memcpy(key_type2, " ", CCA_KEYWORD_SIZE); dll_CSNBKGN2(&return_code, &reason_code, &zero_length, NULL, &rule_array_count, rule_array, &clear_key_length, key_type1, key_type2, &key_name_length, NULL, &key_name_length, NULL, &user_data_length, NULL, &user_data_length, NULL, &zero_length, NULL, &zero_length, NULL, &key_token_length, key_token, &zero_length, NULL); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBKGN2 (HMAC KEY GENERATE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } /* Add the key object to the template */ rc = build_attribute(CKA_IBM_OPAQUE, key_token, key_token_length, &opaque_key); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute(CKA_IBM_OPAQUE) failed\n"); return rc; } rc = template_update_attribute(template, opaque_key); if (rc != CKR_OK) { TRACE_DEVEL("template_update_attribute(CKA_IBM_OPAQUE) failed.\n"); return rc; } return CKR_OK; } static CK_RV ccatok_wrap_key_rsa_pkcs(CK_MECHANISM *mech, CK_BBOOL length_only, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; CK_BYTE buffer[900] = { 0, }; long buffer_len = sizeof(buffer); CK_ATTRIBUTE *attr, *key_opaque, *wrap_key_opaque; CK_OBJECT_CLASS key_class; CK_KEY_TYPE key_type; CK_RSA_PKCS_OAEP_PARAMS *oaep; if (!template_attribute_find(key->template, CKA_CLASS, &attr)) return CKR_KEY_NOT_WRAPPABLE; key_class = *(CK_OBJECT_CLASS *)attr->pValue; if (key_class != CKO_SECRET_KEY) return CKR_KEY_NOT_WRAPPABLE; if (!template_attribute_find(key->template, CKA_KEY_TYPE, &attr)) return CKR_KEY_NOT_WRAPPABLE; key_type = *(CK_KEY_TYPE *) attr->pValue; switch (key_type) { case CKK_DES: case CKK_DES2: case CKK_DES3: switch (mech->mechanism) { case CKM_RSA_PKCS: rule_array_count = 2; memcpy(rule_array, "DES PKCS-1.2", 2 * CCA_KEYWORD_SIZE); break; case CKM_RSA_PKCS_OAEP: rule_array_count = 3; oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter; if (oaep == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA doesn't support non-empty OAEP source data\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "DES PKCSOAEPSHA-1 ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "DES PKCSOAEPSHA-256 ", 3 * CCA_KEYWORD_SIZE); break; default: return CKR_MECHANISM_PARAM_INVALID; } break; default: return CKR_MECHANISM_INVALID; } break; case CKK_AES: switch (mech->mechanism) { case CKM_RSA_PKCS: rule_array_count = 2; memcpy(rule_array, "AES PKCS-1.2", 2 * CCA_KEYWORD_SIZE); break; case CKM_RSA_PKCS_OAEP: rule_array_count = 3; oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter; if (oaep == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source " "data\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "AES PKCSOAEPSHA-1 ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "AES PKCSOAEPSHA-256 ", 3 * CCA_KEYWORD_SIZE); break; default: return CKR_MECHANISM_PARAM_INVALID; } break; default: return CKR_MECHANISM_INVALID; } break; default: return CKR_KEY_NOT_WRAPPABLE; } if (!template_attribute_find(key->template, CKA_IBM_OPAQUE, &key_opaque)) return CKR_KEY_NOT_WRAPPABLE; if (!template_attribute_find(wrapping_key->template, CKA_IBM_OPAQUE, &wrap_key_opaque)) return CKR_KEY_NOT_WRAPPABLE; dll_CSNDSYX(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&key_opaque->ulValueLen, key_opaque->pValue, (long *)&wrap_key_opaque->ulValueLen, wrap_key_opaque->pValue, &buffer_len, buffer); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDSYX (SYMMETRIC KEY EXPORT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } if (length_only) { *wrapped_key_len = buffer_len; return CKR_OK; } if ((CK_ULONG)buffer_len > *wrapped_key_len) { *wrapped_key_len = buffer_len; return CKR_BUFFER_TOO_SMALL; } memcpy(wrapped_key, buffer, buffer_len); *wrapped_key_len = buffer_len; return CKR_OK; } static CK_RV ccatok_unwrap_key_rsa_pkcs(CK_MECHANISM *mech, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len) { long return_code, reason_code, rule_array_count; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; CK_BYTE buffer[3500] = { 0, }; CK_BYTE dummy[AES_KEY_SIZE_256] = { 0, }; long buffer_len = sizeof(buffer); CK_ATTRIBUTE *attr, *wrap_key_opaque,*key_opaque = NULL; CK_ATTRIBUTE *value = NULL, *value_len = NULL; CK_OBJECT_CLASS key_class; CK_KEY_TYPE key_type, cca_key_type; CK_ULONG key_size = 0; CK_RSA_PKCS_OAEP_PARAMS *oaep; uint16_t val; CK_RV rc; if (!template_attribute_find(key->template, CKA_CLASS, &attr)) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; key_class = *(CK_OBJECT_CLASS *)attr->pValue; if (key_class != CKO_SECRET_KEY) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; if (!template_attribute_find(key->template, CKA_KEY_TYPE, &attr)) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; key_type = *(CK_KEY_TYPE *) attr->pValue; switch (key_type) { case CKK_DES: case CKK_DES2: case CKK_DES3: switch (mech->mechanism) { case CKM_RSA_PKCS: rule_array_count = 2; memcpy(rule_array, "DES PKCS-1.2", 2 * CCA_KEYWORD_SIZE); break; case CKM_RSA_PKCS_OAEP: rule_array_count = 3; oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter; if (oaep == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source " "data\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "DES PKCSOAEPSHA-1 ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "DES PKCSOAEPSHA-256 ", 3 * CCA_KEYWORD_SIZE); break; default: return CKR_MECHANISM_PARAM_INVALID; } break; default: return CKR_MECHANISM_INVALID; } break; case CKK_AES: switch (mech->mechanism) { case CKM_RSA_PKCS: rule_array_count = 2; memcpy(rule_array, "AES PKCS-1.2", 2 * CCA_KEYWORD_SIZE); break; case CKM_RSA_PKCS_OAEP: rule_array_count = 3; oaep = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter; if (oaep == NULL || mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) return CKR_MECHANISM_PARAM_INVALID; if (oaep->source == CKZ_DATA_SPECIFIED && oaep->ulSourceDataLen > 0) { TRACE_ERROR("CCA does not support non-empty OAEP source " "data\n"); return CKR_MECHANISM_PARAM_INVALID; } switch (oaep->hashAlg) { case CKM_SHA_1: if (oaep->mgf != CKG_MGF1_SHA1) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "AES PKCSOAEPSHA-1 ", 3 * CCA_KEYWORD_SIZE); break; case CKM_SHA256: if (oaep->mgf != CKG_MGF1_SHA256) return CKR_MECHANISM_PARAM_INVALID; memcpy(rule_array, "AES PKCSOAEPSHA-256 ", 3 * CCA_KEYWORD_SIZE); break; default: return CKR_MECHANISM_PARAM_INVALID; } break; default: return CKR_MECHANISM_INVALID; } break; default: return CKR_WRAPPED_KEY_INVALID; } if (!template_attribute_find(wrapping_key->template, CKA_IBM_OPAQUE, &wrap_key_opaque)) return CKR_TEMPLATE_INCONSISTENT; dll_CSNDSYI(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&wrapped_key_len, wrapped_key, (long *)&wrap_key_opaque->ulValueLen, wrap_key_opaque->pValue, &buffer_len, buffer); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNDSYI (SYMMETRIC KEY IMPORT) failed." " return:%ld, reason:%ld\n", return_code, reason_code); return CKR_FUNCTION_FAILED; } if (buffer[0] != 0x01) { /* Internal key token */ TRACE_DEVEL("key token invalid\n"); return CKR_FUNCTION_FAILED; } switch (buffer[4]) { case 0x00: /* DES key token */ case 0x01: /* DES3 key token */ switch (buffer[59] & 0x30) { case 0x00: cca_key_type = CKK_DES; key_size = DES_KEY_SIZE; break; case 0x10: cca_key_type = CKK_DES2; key_size = 2 * DES_KEY_SIZE; break; case 0x20: cca_key_type = CKK_DES3; key_size = 3 * DES_KEY_SIZE; break; default: TRACE_DEVEL("key token invalid\n"); return CKR_FUNCTION_FAILED; } break; case 0x04:/* AES key token */ cca_key_type = CKK_AES; memcpy(&val, &buffer[56], sizeof(val)); key_size = ntohs(val) / 8; break; default: TRACE_DEVEL("key token invalid\n"); return CKR_FUNCTION_FAILED; } if (key_type != cca_key_type) { TRACE_DEVEL("Wrong key type\n"); return CKR_FUNCTION_FAILED; } rc = build_attribute(CKA_IBM_OPAQUE, buffer, buffer_len, &key_opaque); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = build_attribute(CKA_VALUE, dummy, key_size, &value); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } switch (key_type) { case CKK_GENERIC_SECRET: case CKK_AES: rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&key_size, sizeof(CK_ULONG), &value_len); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } break; default: break; } template_update_attribute(key->template, key_opaque); template_update_attribute(key->template, value); if (value_len != NULL) template_update_attribute(key->template, value_len); return CKR_OK; error: if (key_opaque) free(key_opaque); if (value) free(value); if (value_len) free(value_len); return rc; } CK_RV token_specific_key_wrap(STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM *mech, CK_BBOOL length_only, OBJECT *wrapping_key, OBJECT *key, CK_BYTE *wrapped_key, CK_ULONG *wrapped_key_len, CK_BBOOL *not_opaque) { CK_ATTRIBUTE *attr; CK_OBJECT_CLASS wrap_key_class; CK_KEY_TYPE wrap_key_type; UNUSED(tokdata); UNUSED(session); *not_opaque = FALSE; if (!template_attribute_find(wrapping_key->template, CKA_CLASS, &attr)) return CKR_KEY_NOT_WRAPPABLE; wrap_key_class = *(CK_OBJECT_CLASS *)attr->pValue; if (!template_attribute_find(wrapping_key->template, CKA_KEY_TYPE, &attr)) return CKR_KEY_NOT_WRAPPABLE; wrap_key_type = *(CK_KEY_TYPE *) attr->pValue; switch (mech->mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: if (wrap_key_class != CKO_PUBLIC_KEY && wrap_key_type != CKK_RSA) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; return ccatok_wrap_key_rsa_pkcs(mech, length_only, wrapping_key, key, wrapped_key, wrapped_key_len); default: return CKR_MECHANISM_INVALID; } } CK_RV token_specific_key_unwrap(STDLL_TokData_t *tokdata, SESSION *session, CK_MECHANISM *mech, CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len, OBJECT *unwrapping_key, OBJECT *unwrapped_key, CK_BBOOL *not_opaque) { CK_ATTRIBUTE *attr; CK_ATTRIBUTE *local = NULL, *always_sens = NULL, *sensitive = NULL; CK_ATTRIBUTE *extractable = NULL, *never_extract = NULL; CK_OBJECT_CLASS unwrap_key_class; CK_KEY_TYPE unwrap_keytype; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_RV rc; UNUSED(tokdata); UNUSED(session); *not_opaque = FALSE; if (!template_attribute_find(unwrapping_key->template, CKA_CLASS, &attr)) return CKR_KEY_NOT_WRAPPABLE; unwrap_key_class = *(CK_OBJECT_CLASS *)attr->pValue; if (!template_attribute_find(unwrapping_key->template, CKA_KEY_TYPE, &attr)) return CKR_KEY_NOT_WRAPPABLE; unwrap_keytype = *(CK_KEY_TYPE *) attr->pValue; switch (mech->mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: if (unwrap_key_class != CKO_PRIVATE_KEY && unwrap_keytype != CKK_RSA) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; rc = ccatok_unwrap_key_rsa_pkcs(mech, unwrapping_key, unwrapped_key, wrapped_key, wrapped_key_len); if (rc != CKR_OK) goto error; break; default: return CKR_MECHANISM_INVALID; } /* * make sure * CKA_LOCAL == FALSE * CKA_ALWAYS_SENSITIVE == FALSE * CKA_EXTRACTABLE == TRUE * CKA_NEVER_EXTRACTABLE == FALSE */ rc = build_attribute(CKA_LOCAL, &false, 1, &local); if (rc != CKR_OK) { TRACE_DEVEL("build attribute failed\n"); goto error; } rc = build_attribute(CKA_ALWAYS_SENSITIVE, &false, 1, &always_sens); if (rc != CKR_OK) { TRACE_DEVEL("build attribute failed\n"); goto error; } rc = build_attribute(CKA_SENSITIVE, &false, 1, &sensitive); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = build_attribute(CKA_EXTRACTABLE, &true, 1, &extractable); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } rc = build_attribute(CKA_NEVER_EXTRACTABLE, &false, 1, &never_extract); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto error; } template_update_attribute(unwrapped_key->template, local); template_update_attribute(unwrapped_key->template, always_sens); template_update_attribute(unwrapped_key->template, sensitive); template_update_attribute(unwrapped_key->template, extractable); template_update_attribute(unwrapped_key->template, never_extract); return CKR_OK; error: if (local) free(local); if (extractable) free(extractable); if (always_sens) free(always_sens); if (never_extract) free(never_extract); return rc; } CK_RV token_specific_reencrypt_single(STDLL_TokData_t *tokdata, SESSION *session, ENCR_DECR_CONTEXT *decr_ctx, CK_MECHANISM *decr_mech, OBJECT *decr_key_obj, ENCR_DECR_CONTEXT *encr_ctx, CK_MECHANISM *encr_mech, OBJECT *encr_key_obj, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_ATTRIBUTE *decr_key_opaque, *encr_key_opaque; long return_code, reason_code, rule_array_count = 0; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; CK_BYTE in_iv[AES_BLOCK_SIZE] = { 0 }; CK_BYTE out_iv[AES_BLOCK_SIZE] = { 0 }; long in_iv_len = 0, out_iv_len = 0; CK_BYTE cv[128] = { 0 }; long cv_len = 128, zero = 0; CK_ULONG max_clear_len, req_out_len; UNUSED(tokdata); UNUSED(session); UNUSED(decr_ctx); UNUSED(encr_ctx); if (!template_attribute_find(decr_key_obj->template, CKA_IBM_OPAQUE, &decr_key_opaque)) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the decryption key.\n"); return CKR_FUNCTION_FAILED; } if (!template_attribute_find(encr_key_obj->template, CKA_IBM_OPAQUE, &encr_key_opaque)) { TRACE_ERROR("Could not find CKA_IBM_OPAQUE for the encryption key.\n"); return CKR_FUNCTION_FAILED; } /* CCA only supports AES-ECB/CBC, and 3DES-CBC with CSNBCTT2 */ switch (decr_mech->mechanism) { case CKM_AES_ECB: rule_array_count = 2; memcpy(rule_array, "IKEY-AESI-ECB ", 2 * CCA_KEYWORD_SIZE); max_clear_len = in_data_len; break; case CKM_AES_CBC: rule_array_count = 2; memcpy(rule_array, "IKEY-AESI-CBC ", 2 * CCA_KEYWORD_SIZE); in_iv_len = decr_mech->ulParameterLen; if (in_iv_len != AES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(in_iv, decr_mech->pParameter, in_iv_len); max_clear_len = in_data_len; break; case CKM_AES_CBC_PAD: rule_array_count = 2; memcpy(rule_array, "IKEY-AESIPKCSPAD", 2 * CCA_KEYWORD_SIZE); in_iv_len = decr_mech->ulParameterLen; if (in_iv_len != AES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(in_iv, decr_mech->pParameter, in_iv_len); /* PKCS#7 pads at least 1 byte in any case */ max_clear_len = in_data_len - 1; break; case CKM_DES3_CBC: rule_array_count = 2; memcpy(rule_array, "IKEY-DESI-CBC ", 2 * CCA_KEYWORD_SIZE); in_iv_len = decr_mech->ulParameterLen; if (in_iv_len != DES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(in_iv, decr_mech->pParameter, in_iv_len); max_clear_len = in_data_len; break; default: TRACE_DEVEL("Decryption method %lu not supported\n", decr_mech->mechanism); return CKR_MECHANISM_INVALID; } switch (encr_mech->mechanism) { case CKM_AES_ECB: memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "OKEY-AESO-ECB ", 2 * CCA_KEYWORD_SIZE); rule_array_count += 2; /* Round up to the next block size */ req_out_len = (max_clear_len / AES_BLOCK_SIZE) * AES_BLOCK_SIZE + (max_clear_len % AES_BLOCK_SIZE ? AES_BLOCK_SIZE : 0); break; case CKM_AES_CBC: memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "OKEY-AESO-CBC ", 2 * CCA_KEYWORD_SIZE); rule_array_count += 2; out_iv_len = encr_mech->ulParameterLen; if (out_iv_len != AES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(out_iv, encr_mech->pParameter, out_iv_len); /* Round up to the next block size */ req_out_len = (max_clear_len / AES_BLOCK_SIZE) * AES_BLOCK_SIZE + (max_clear_len % AES_BLOCK_SIZE ? AES_BLOCK_SIZE : 0); break; case CKM_AES_CBC_PAD: memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "OKEY-AESOPKCSPAD", 2 * CCA_KEYWORD_SIZE); rule_array_count += 2; out_iv_len = encr_mech->ulParameterLen; if (out_iv_len != AES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(out_iv, encr_mech->pParameter, out_iv_len); /* PKCS#7 pads a full block, if already a multiple of the block size */ req_out_len = AES_BLOCK_SIZE * (max_clear_len / AES_BLOCK_SIZE + 1); break; case CKM_DES3_CBC: memcpy(rule_array + (rule_array_count * CCA_KEYWORD_SIZE), "OKEY-DESO-CBC ", 2 * CCA_KEYWORD_SIZE); rule_array_count += 2; out_iv_len = encr_mech->ulParameterLen; if (out_iv_len != DES_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID; memcpy(out_iv, encr_mech->pParameter, out_iv_len); /* Round up to the next block size */ req_out_len = (max_clear_len / DES_BLOCK_SIZE) * DES_BLOCK_SIZE + (max_clear_len % DES_BLOCK_SIZE ? DES_BLOCK_SIZE : 0); break; default: TRACE_DEVEL("Encryption method %lu not supported\n", decr_mech->mechanism); return CKR_MECHANISM_INVALID; } if (out_data == NULL) { *out_data_len = req_out_len; return CKR_OK; } if (*out_data_len < req_out_len) { *out_data_len = req_out_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } dll_CSNBCTT2(&return_code, &reason_code, NULL, NULL, &rule_array_count, rule_array, (long *)&decr_key_opaque->ulValueLen, decr_key_opaque->pValue, &in_iv_len, in_iv, (long *)&in_data_len, in_data, &cv_len, cv, (long *)&encr_key_opaque->ulValueLen, encr_key_opaque->pValue, &out_iv_len, out_iv, (long *)out_data_len, out_data, &zero, NULL, &zero, NULL); if (return_code != CCA_SUCCESS) { TRACE_ERROR("CSNBCTT2 (CIPHER TEXT TRANSLATE) failed." " return:%ld, reason:%ld\n", return_code, reason_code); if (return_code == 8 && reason_code == 72) return CKR_DATA_LEN_RANGE; return CKR_FUNCTION_FAILED; } return CKR_OK; }