/* * 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 */ // File: mech_aes.c // // Mechanisms for AES // #include // for memcmp() et al #include #include "pkcs11types.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "tok_spec_struct.h" #include "trace.h" #include // // CK_RV aes_ecb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key = NULL; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (in_data_len % AES_BLOCK_SIZE != 0) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } 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 (length_only == TRUE) { *out_data_len = in_data_len; rc = CKR_OK; goto done; } if (*out_data_len < in_data_len) { *out_data_len = in_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto done; } rc = ckm_aes_ecb_encrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key); done: object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_ecb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key = NULL; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // CKM_DES3_ECB requires the input data to be an integral // multiple of the block size // if (in_data_len % AES_BLOCK_SIZE != 0) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); return CKR_ENCRYPTED_DATA_LEN_RANGE; } 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 (length_only == TRUE) { *out_data_len = in_data_len; rc = CKR_OK; goto done; } if (*out_data_len < in_data_len) { *out_data_len = in_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto done; } rc = ckm_aes_ecb_decrypt(tokdata, in_data, in_data_len, out_data, out_data_len, key); done: object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_cbc_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key = NULL; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // CKM_DES3_CBC requires the input data to be an integral // multiple of the block size // if (in_data_len % AES_BLOCK_SIZE != 0) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } 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 (length_only == TRUE) { *out_data_len = in_data_len; rc = CKR_OK; goto done; } if (*out_data_len < in_data_len) { *out_data_len = in_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto done; } rc = ckm_aes_cbc_encrypt(tokdata, in_data, in_data_len, out_data, out_data_len, ctx->mech.pParameter, key); done: object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_cbc_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key = NULL; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // CKM_DES3_CBC requires the input data to be an integral // multiple of the block size // if (in_data_len % AES_BLOCK_SIZE != 0) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); return CKR_ENCRYPTED_DATA_LEN_RANGE; } 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 (length_only == TRUE) { *out_data_len = in_data_len; rc = CKR_OK; goto done; } if (*out_data_len < in_data_len) { *out_data_len = in_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto done; } rc = ckm_aes_cbc_decrypt(tokdata, in_data, in_data_len, out_data, out_data_len, ctx->mech.pParameter, key); done: object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_cbc_pad_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key = NULL; CK_BYTE *clear = NULL; CK_ULONG padded_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // AES-CBC-PAD has no input length requirements // 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; } // compute the output length, accounting for padding // padded_len = AES_BLOCK_SIZE * (in_data_len / AES_BLOCK_SIZE + 1); if (length_only == TRUE) { *out_data_len = padded_len; rc = CKR_OK; goto done; } if (*out_data_len < padded_len) { *out_data_len = padded_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto done; } clear = (CK_BYTE *) malloc(padded_len); if (!clear) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } if (in_data != NULL && in_data_len > 0) memcpy(clear, in_data, in_data_len); add_pkcs_padding(clear + in_data_len, AES_BLOCK_SIZE, in_data_len, padded_len); rc = ckm_aes_cbc_encrypt(tokdata, clear, padded_len, out_data, out_data_len, ctx->mech.pParameter, key); free(clear); done: object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_cbc_pad_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key = NULL; CK_BYTE *clear = NULL; CK_ULONG padded_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // // no need to validate the input length since we'll pad as necessary // 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; } // we're decrypting so even with CBC-PAD, we should have an integral // number of block to decrypt // if (in_data_len % AES_BLOCK_SIZE != 0) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; goto done; } // the amount of cleartext after stripping the padding will actually be less // than the input bytes... // padded_len = in_data_len; if (length_only == TRUE) { *out_data_len = padded_len; rc = CKR_OK; goto done; } clear = (CK_BYTE *) malloc(padded_len); if (!clear) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } rc = ckm_aes_cbc_decrypt(tokdata, in_data, in_data_len, clear, &padded_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { strip_pkcs_padding(clear, padded_len, out_data_len); memcpy(out_data, clear, *out_data_len); } free(clear); done: object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_ctr_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key = NULL; CK_RV rc; CK_AES_CTR_PARAMS *aesctr = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (in_data_len % AES_BLOCK_SIZE != 0) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } 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 (length_only == TRUE) { *out_data_len = in_data_len; rc = CKR_OK; goto done; } if (*out_data_len < in_data_len) { *out_data_len = in_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto done; } aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; rc = ckm_aes_ctr_encrypt(tokdata, in_data, in_data_len, out_data, out_data_len, (CK_BYTE *) aesctr->cb, (CK_ULONG) aesctr->ulCounterBits, key); done: object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_ctr_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key = NULL; CK_RV rc; CK_AES_CTR_PARAMS *aesctr = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (in_data_len % AES_BLOCK_SIZE != 0) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); return CKR_ENCRYPTED_DATA_LEN_RANGE; } 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 (length_only == TRUE) { *out_data_len = in_data_len; rc = CKR_OK; goto done; } if (*out_data_len < in_data_len) { *out_data_len = in_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); rc = CKR_BUFFER_TOO_SMALL; goto done; } aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; rc = ckm_aes_ctr_decrypt(tokdata, in_data, in_data_len, out_data, out_data_len, (CK_BYTE *) aesctr->cb, (CK_ULONG) aesctr->ulCounterBits, key); done: object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_ecb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE *clear = NULL; CK_ULONG total, remain, out_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad arguments\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we have at least 1 block // remain = (total % AES_BLOCK_SIZE); out_len = (total - remain); // should always be at least 1 block if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } clear = (CK_BYTE *) malloc(out_len); if (!clear) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); object_put(tokdata, key, TRUE); key = NULL; return CKR_HOST_MEMORY; } // copy any data left over from the previous encryption operation first // memcpy(clear, context->data, context->len); memcpy(clear + context->len, in_data, out_len - context->len); rc = ckm_aes_ecb_encrypt(tokdata, clear, out_len, out_data, out_data_len, key); if (rc == CKR_OK) { *out_data_len = out_len; // update the context buffer. we already used the buffer's current // contents so we completely overwrite it // if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } free(clear); object_put(tokdata, key, TRUE); key = NULL; return rc; } } // // CK_RV aes_ecb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we have at least 1 block // remain = (total % AES_BLOCK_SIZE); out_len = total - remain; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); object_put(tokdata, key, TRUE); key = NULL; return CKR_HOST_MEMORY; } // copy any data left over from the previous decryption operation first // memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = ckm_aes_ecb_decrypt(tokdata, cipher, out_len, out_data, out_data_len, key); if (rc == CKR_OK) { *out_data_len = out_len; // copy the remaining 'new' input data to the context buffer // if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } free(cipher); object_put(tokdata, key, TRUE); key = NULL; return rc; } } // // CK_RV aes_cbc_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE *clear = NULL; CK_ULONG total, remain, out_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we have at least 1 block // remain = (total % AES_BLOCK_SIZE); out_len = total - remain; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } // these buffers need to be longword aligned // clear = (CK_BYTE *) malloc(out_len); if (!clear) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); object_put(tokdata, key, TRUE); key = NULL; return CKR_HOST_MEMORY; } // copy any data left over from the previous encryption operation first // memcpy(clear, context->data, context->len); memcpy(clear + context->len, in_data, out_len - context->len); rc = ckm_aes_cbc_encrypt(tokdata, clear, out_len, out_data, out_data_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { *out_data_len = out_len; // the new init_v is the last encrypted data block // memcpy(ctx->mech.pParameter, out_data + (*out_data_len - AES_BLOCK_SIZE), AES_BLOCK_SIZE); // copy the remaining 'new' input data to the context buffer // if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } free(clear); object_put(tokdata, key, TRUE); key = NULL; return rc; } } // // CK_RV aes_cbc_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = context->len + in_data_len; if (total < AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we have at least 1 block // remain = total % AES_BLOCK_SIZE; out_len = total - remain; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } // these buffers need to be longword aligned // cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); object_put(tokdata, key, TRUE); key = NULL; return CKR_HOST_MEMORY; } // copy any data left over from the previous decryption operation first // memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = ckm_aes_cbc_decrypt(tokdata, cipher, out_len, out_data, out_data_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { *out_data_len = out_len; // the new init_v is the last input data block // memcpy(ctx->mech.pParameter, cipher + (out_len - AES_BLOCK_SIZE), AES_BLOCK_SIZE); // copy the remaining 'new' input data to the context buffer // if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } free(cipher); object_put(tokdata, key, TRUE); key = NULL; return rc; } } // // CK_RV aes_cbc_pad_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE *clear = NULL; CK_ULONG total, remain, out_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); // note, this is subtly different from the other encrypt update routines // if (total <= AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { remain = (total % AES_BLOCK_SIZE); out_len = total - remain; // out_len is a multiple of AES_BLOCK_SIZE if (remain == 0) { remain = AES_BLOCK_SIZE; out_len -= AES_BLOCK_SIZE; } if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } // at this point, we should have: // 1) remain != 0 // 2) out_len != 0 // rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } // these buffers need to be longword aligned // clear = (CK_BYTE *) malloc(out_len); if (!clear) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); object_put(tokdata, key, TRUE); key = NULL; return CKR_HOST_MEMORY; } // copy any data left over from the previous encryption operation first // memcpy(clear, context->data, context->len); memcpy(clear + context->len, in_data, out_len - context->len); // // we don't do padding during the update // rc = ckm_aes_cbc_encrypt(tokdata, clear, out_len, out_data, out_data_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { // the new init_v is the last encrypted data block // memcpy(ctx->mech.pParameter, out_data + (*out_data_len - AES_BLOCK_SIZE), AES_BLOCK_SIZE); // copy the remaining 'new' input data to the temporary space // if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } free(clear); object_put(tokdata, key, TRUE); key = NULL; return rc; } } // // CK_RV aes_cbc_pad_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); // note, this is subtly different from the other decrypt update routines // if (total <= AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we have at least 1 block + 1 byte // remain = total % AES_BLOCK_SIZE; out_len = total - remain; if (remain == 0) { remain = AES_BLOCK_SIZE; out_len -= AES_BLOCK_SIZE; } if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } // at this point, we should have: // 1) remain != 0 // 2) out_len != 0 // rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } // these buffers need to be longword aligned // cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); object_put(tokdata, key, TRUE); key = NULL; return CKR_HOST_MEMORY; } // copy any data left over from the previous decryption operation first // memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = ckm_aes_cbc_decrypt(tokdata, cipher, out_len, out_data, out_data_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { // the new init_v is the last input data block // memcpy(ctx->mech.pParameter, cipher + (out_len - AES_BLOCK_SIZE), AES_BLOCK_SIZE); // copy the remaining 'new' input data to the temporary space // if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } free(cipher); object_put(tokdata, key, TRUE); key = NULL; return rc; } } // // CK_RV aes_ctr_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE *clear = NULL; CK_ULONG total, remain, out_len; CK_RV rc; CK_AES_CTR_PARAMS *aesctr = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we atleast have 1 block remain = (total % AES_BLOCK_SIZE); out_len = total - remain; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } //these buffers need to be longword aligned clear = (CK_BYTE *) malloc(out_len); if (!clear) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); object_put(tokdata, key, TRUE); key = NULL; return CKR_HOST_MEMORY; } //copy all the leftover data from the previous encryption operation //first memcpy(clear, context->data, context->len); memcpy(clear + context->len, in_data, out_len - context->len); aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; rc = ckm_aes_ctr_encrypt(tokdata, clear, out_len, out_data, out_data_len, (CK_BYTE *) aesctr->cb, (CK_ULONG) aesctr->ulCounterBits, key); if (rc == CKR_OK) { *out_data_len = out_len; // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } free(clear); object_put(tokdata, key, TRUE); key = NULL; return rc; } } // // CK_RV aes_ctr_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE *clear = NULL; CK_ULONG total, remain, out_len; CK_RV rc; CK_AES_CTR_PARAMS *aesctr = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we atleast have 1 block remain = (total % AES_BLOCK_SIZE); out_len = total - remain; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } //these buffers need to be longword aligned clear = (CK_BYTE *) malloc(out_len); if (!clear) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); object_put(tokdata, key, TRUE); key = NULL; return CKR_HOST_MEMORY; } //copy all the leftover data from the previous encryption operation //first memcpy(clear, context->data, context->len); memcpy(clear + context->len, in_data, out_len - context->len); aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; rc = ckm_aes_ctr_decrypt(tokdata, clear, out_len, out_data, out_data_len, (CK_BYTE *) aesctr->cb, (CK_ULONG) aesctr->ulCounterBits, key); if (rc == CKR_OK) { *out_data_len = out_len; // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } free(clear); object_put(tokdata, key, TRUE); key = NULL; return rc; } } // // CK_RV aes_ecb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; UNUSED(tokdata); UNUSED(out_data); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // satisfy the compiler // if (length_only) context = NULL; context = (AES_CONTEXT *) ctx->context; // DES3-ECB does no padding so there had better not be // any data in the context buffer. if there is it means // that the overall data length was not a multiple of the blocksize // if (context->len != 0) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } *out_data_len = 0; return CKR_OK; } // // CK_RV aes_ecb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; UNUSED(tokdata); UNUSED(out_data); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // satisfy the compiler // if (length_only) context = NULL; context = (AES_CONTEXT *) ctx->context; // DES3-ECB does no padding so there had better not be // any data in the context buffer. if there is it means // that the overall data length was not a multiple of the blocksize // if (context->len != 0) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); return CKR_ENCRYPTED_DATA_LEN_RANGE; } *out_data_len = 0; return CKR_OK; } // // CK_RV aes_cbc_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; UNUSED(tokdata); UNUSED(out_data); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // satisfy the compiler // if (length_only) context = NULL; context = (AES_CONTEXT *) ctx->context; // DES3-CBC does no padding so there had better not be // any data in the context buffer. if there is it means // that the overall data length was not a multiple of the blocksize // if (context->len != 0) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } *out_data_len = 0; return CKR_OK; } // // CK_RV aes_cbc_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; UNUSED(tokdata); UNUSED(out_data); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // satisfy the compiler // if (length_only) context = NULL; context = (AES_CONTEXT *) ctx->context; if (context->len != 0) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); return CKR_ENCRYPTED_DATA_LEN_RANGE; } *out_data_len = 0; return CKR_OK; } // // CK_RV aes_cbc_pad_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE clear[2 * AES_BLOCK_SIZE]; CK_ULONG out_len; CK_RV rc; if (!sess || !ctx || !out_data_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; } context = (AES_CONTEXT *) ctx->context; // there will never be more than one block in the context buffer // so the amount of output is as follows: // if less than 1 block stored, we generate one block of output // if a full block is stored, we generate two blocks of output (one pad // block) // if (context->len == AES_BLOCK_SIZE) out_len = 2 * AES_BLOCK_SIZE; else out_len = AES_BLOCK_SIZE; if (length_only == TRUE) { *out_data_len = out_len; rc = CKR_OK; } else { memcpy(clear, context->data, context->len); add_pkcs_padding(clear + context->len, AES_BLOCK_SIZE, context->len, out_len); rc = ckm_aes_cbc_encrypt(tokdata, clear, out_len, out_data, out_data_len, ctx->mech.pParameter, key); } object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_cbc_pad_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; OBJECT *key = NULL; CK_BYTE clear[AES_BLOCK_SIZE]; CK_ULONG out_len; CK_RV rc; if (!sess || !ctx || !out_data_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; } context = (AES_CONTEXT *) ctx->context; // there had better be a full block in the context buffer // if (context->len != AES_BLOCK_SIZE) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; goto done; } // we don't know a priori how much data we'll be returning. we won't // know until after we decrypt it and strip the padding. it's possible // that we'll return nothing (the final block might be a padding block). // out_len = AES_BLOCK_SIZE; // upper bound on what we'll return if (length_only == TRUE) { *out_data_len = out_len; rc = CKR_OK; } else { rc = ckm_aes_cbc_decrypt(tokdata, context->data, AES_BLOCK_SIZE, clear, &out_len, ctx->mech.pParameter, key); if (rc == CKR_OK) { strip_pkcs_padding(clear, out_len, &out_len); if (out_len != 0) memcpy(out_data, clear, out_len); *out_data_len = out_len; } } done: object_put(tokdata, key, TRUE); key = NULL; return rc; } // // CK_RV aes_ctr_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; CK_AES_CTR_PARAMS *aesctr = NULL; UNUSED(tokdata); UNUSED(out_data); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // satisfy the compiler // if (length_only) context = NULL; context = (AES_CONTEXT *) ctx->context; // DES3-CBC does no padding so there had better not be // any data in the context buffer. if there is it means // that the overall data length was not a multiple of the blocksize // if (context->len != 0) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; //to check that the counter buffer doesnot overflow if (((CK_ULONG) aesctr->ulCounterBits) > ((CK_ULONG) aesctr->ulCounterBits + 1)) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } *out_data_len = 0; return CKR_OK; } // // CK_RV aes_ctr_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; CK_AES_CTR_PARAMS *aesctr = NULL; UNUSED(tokdata); UNUSED(out_data); if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // satisfy the compiler // if (length_only) context = NULL; context = (AES_CONTEXT *) ctx->context; // DES3-CBC does no padding so there had better not be // any data in the context buffer. if there is it means // that the overall data length was not a multiple of the blocksize // if (context->len != 0) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); return CKR_ENCRYPTED_DATA_LEN_RANGE; } aesctr = (CK_AES_CTR_PARAMS *) ctx->mech.pParameter; //to check that the counter buffer doesnot overflow if (((CK_ULONG) aesctr->ulCounterBits) > ((CK_ULONG) aesctr->ulCounterBits + 1)) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); return CKR_DATA_LEN_RANGE; } *out_data_len = 0; return CKR_OK; } CK_RV aes_ofb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_ULONG rc; OBJECT *key_obj = NULL; if (!sess || !ctx || !in_data || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { *out_data_len = in_data_len; return CKR_OK; } if (*out_data_len < in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_ofb(tokdata, in_data, in_data_len, out_data, key_obj, ctx->mech.pParameter, 1); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes ofb encrypt failed.\n"); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV aes_ofb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; CK_RV rc; OBJECT *key_obj = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we have at least 1 block remain = (total % AES_BLOCK_SIZE); out_len = total - remain; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } if (*out_data_len < out_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } // copy any data left over from the previous encryption operation first memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = token_specific.t_aes_ofb(tokdata, cipher, out_len, out_data, key_obj, ctx->mech.pParameter, 1); if (rc == CKR_OK) { *out_data_len = out_len; // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } else { TRACE_DEVEL("Token specific aes ofb encrypt failed.\n"); } free(cipher); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_ofb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key_obj = NULL; AES_CONTEXT *context = NULL; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; // there will never be more than one block in the context buffer // so the amount of output is as follows: // if less than 1 block stored, we generate same length of output data // if no data stored, no data can be returned (length zero) if (length_only == TRUE) { *out_data_len = context->len; return CKR_OK; } else { if (context->len == 0) { *out_data_len = 0; return CKR_OK; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_ofb(tokdata, context->data, context->len, out_data, key_obj, ctx->mech.pParameter, 1); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes ofb encrypt failed.\n"); object_put(tokdata, key_obj, TRUE); key_obj = NULL; *out_data_len = context->len; return rc; } } CK_RV aes_ofb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_ULONG rc; OBJECT *key_obj = NULL; if (!sess || !ctx || !in_data || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { *out_data_len = in_data_len; return CKR_OK; } if (*out_data_len < in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_ofb(tokdata, in_data, in_data_len, out_data, key_obj, ctx->mech.pParameter, 0); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes ofb decrypt failed.\n"); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV aes_ofb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_CONTEXT *context = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; CK_RV rc; OBJECT *key_obj = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < AES_BLOCK_SIZE) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we have at least 1 block remain = (total % AES_BLOCK_SIZE); out_len = total - remain; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } if (*out_data_len < out_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } // copy any data left over from the previous decryption operation first memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = token_specific.t_aes_ofb(tokdata, cipher, out_len, out_data, key_obj, ctx->mech.pParameter, 0); if (rc == CKR_OK) { *out_data_len = out_len; // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } else { TRACE_DEVEL("Token specific aes ofb decrypt failed.\n"); } free(cipher); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_ofb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { OBJECT *key_obj = NULL; AES_CONTEXT *context = NULL; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } // satisfy the compiler //if (length_only) // context = NULL; context = (AES_CONTEXT *) ctx->context; // there will never be more than one block in the context buffer // so the amount of output is as follows: // if less than 1 block stored, we generate same length of output data // if no data stored, no data can be returned (length zero) if (length_only == TRUE) { *out_data_len = context->len; return CKR_OK; } else { if (context->len == 0) { *out_data_len = 0; return CKR_OK; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_ofb(tokdata, context->data, context->len, out_data, key_obj, ctx->mech.pParameter, 0); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes ofb decrypt failed.\n"); object_put(tokdata, key_obj, TRUE); key_obj = NULL; *out_data_len = context->len; return rc; } } CK_RV aes_cfb_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_ULONG cfb_len) { CK_ULONG rc; OBJECT *key_obj = NULL; if (!sess || !ctx || !in_data || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { *out_data_len = in_data_len; return CKR_OK; } if (*out_data_len < in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_cfb(tokdata, in_data, in_data_len, out_data, key_obj, ctx->mech.pParameter, cfb_len, 1); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes cfb encrypt failed.\n"); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV aes_cfb_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_ULONG cfb_len) { AES_CONTEXT *context = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; CK_RV rc; OBJECT *key_obj = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < cfb_len) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we have at least 1 block remain = (total % cfb_len); out_len = total - remain; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } if (*out_data_len < out_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } // copy any data left over from the previous encryption operation first memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = token_specific.t_aes_cfb(tokdata, cipher, out_len, out_data, key_obj, ctx->mech.pParameter, cfb_len, 1); if (rc == CKR_OK) { *out_data_len = out_len; // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } else { TRACE_DEVEL("Token specific aes cfb encrypt failed.\n"); } free(cipher); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_cfb_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_ULONG cfb_len) { OBJECT *key_obj = NULL; AES_CONTEXT *context = NULL; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; // there will never be more than one block in the context buffer // so the amount of output is as follows: // if less than 1 block stored, we generate same length of output data // if no data stored, no data can be returned (length zero) if (context->len == 0) { *out_data_len = 0; return CKR_OK; } if (length_only == TRUE) { *out_data_len = context->len; return CKR_OK; } else { rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_cfb(tokdata, context->data, context->len, out_data, key_obj, ctx->mech.pParameter, cfb_len, 1); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes cfb encrypt failed.\n"); *out_data_len = context->len; object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_cfb_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_ULONG cfb_len) { CK_ULONG rc; OBJECT *key_obj = NULL; if (!sess || !ctx || !in_data || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { *out_data_len = in_data_len; return CKR_OK; } if (*out_data_len < in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_cfb(tokdata, in_data, in_data_len, out_data, key_obj, ctx->mech.pParameter, cfb_len, 0); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes cfb decrypt failed.\n"); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV aes_cfb_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_ULONG cfb_len) { AES_CONTEXT *context = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; CK_RV rc; OBJECT *key_obj = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < cfb_len) { if (length_only == FALSE && in_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; } *out_data_len = 0; return CKR_OK; } else { // we have at least 1 block remain = (total % cfb_len); out_len = total - remain; if (length_only == TRUE) { *out_data_len = out_len; return CKR_OK; } if (*out_data_len < out_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } // copy any data left over from the previous decryption operation first memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = token_specific.t_aes_cfb(tokdata, cipher, out_len, out_data, key_obj, ctx->mech.pParameter, cfb_len, 0); if (rc == CKR_OK) { *out_data_len = out_len; // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } else { TRACE_DEVEL("Token specific aes cfb decrypt failed.\n"); } free(cipher); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_cfb_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_ULONG cfb_len) { OBJECT *key_obj = NULL; AES_CONTEXT *context = NULL; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CONTEXT *) ctx->context; // there will never be more than one block in the context buffer // so the amount of output is as follows: // if less than 1 block stored, we generate same length of output data // if no data stored, no data can be returned (length zero) if (context->len == 0) { *out_data_len = 0; return CKR_OK; } if (length_only == TRUE) { *out_data_len = context->len; return CKR_OK; } else { rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_cfb(tokdata, context->data, context->len, out_data, key_obj, ctx->mech.pParameter, cfb_len, 0); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes cfb decrypt failed.\n"); *out_data_len = context->len; object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_mac_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_ULONG rc; OBJECT *key_obj = NULL; CK_ULONG mac_len; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (ctx->mech.pParameter) mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; else mac_len = AES_BLOCK_SIZE / 2; if (length_only == TRUE) { *out_data_len = mac_len; return CKR_OK; } if ((in_data_len % AES_BLOCK_SIZE) != 0) { rc = aes_mac_sign_update(tokdata, sess, ctx, in_data, in_data_len); if (rc != CKR_OK) return rc; rc = aes_mac_sign_final(tokdata, sess, length_only, ctx, out_data, out_data_len); return rc; } else { if (*out_data_len < mac_len) { *out_data_len = mac_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_mac(tokdata, in_data, in_data_len, key_obj, ((AES_DATA_CONTEXT *) ctx->context)->iv); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes mac failed.\n"); object_put(tokdata, key_obj, TRUE); key_obj = NULL; memcpy(out_data, ((AES_DATA_CONTEXT *) ctx->context)->iv, mac_len); *out_data_len = mac_len; return rc; } } CK_RV aes_mac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len) { CK_ULONG rc; OBJECT *key_obj = NULL; AES_DATA_CONTEXT *context = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; if (!sess || !ctx) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_DATA_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < AES_BLOCK_SIZE) { if (in_data_len > 0) memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; return CKR_OK; } else { // we have at least 1 block remain = (total % AES_BLOCK_SIZE); out_len = total - remain; rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } // copy any data left over from the previous signUpdate operation first memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = token_specific.t_aes_mac(tokdata, cipher, out_len, key_obj, context->iv); if (rc == CKR_OK) { // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } else { TRACE_DEVEL("Token specific aes mac failed.\n"); } free(cipher); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_mac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_ULONG rc = CKR_OK; CK_ULONG mac_len; AES_DATA_CONTEXT *context = NULL; OBJECT *key_obj = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_DATA_CONTEXT *) ctx->context; if (ctx->mech.pParameter) mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; else mac_len = AES_BLOCK_SIZE / 2; // there will never be more than one block in the context buffer // so the amount of output is as follows: // if less than 1 block stored, we generate one block of output (with // padding) // if no data stored, we are done (take the cipher from previous round) if (length_only == TRUE) { *out_data_len = mac_len; return CKR_OK; } if (context->len > 0) { if (*out_data_len < mac_len) { *out_data_len = mac_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } /* padding with '00' in case case we didn't reach block size */ memset(context->data + context->len, 0x0, AES_BLOCK_SIZE - context->len); rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_mac(tokdata, context->data, AES_BLOCK_SIZE, key_obj, context->iv); object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (rc != CKR_OK) { TRACE_DEVEL("Token Specific aes mac failed.\n"); return rc; } } memcpy(out_data, context->iv, mac_len); *out_data_len = mac_len; return rc; } CK_RV aes_mac_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_ULONG rc; OBJECT *key_obj = NULL; CK_ULONG mac_len; if (!sess || !ctx || !in_data || !out_data) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if ((in_data_len % AES_BLOCK_SIZE) != 0) { rc = aes_mac_verify_update(tokdata, sess, ctx, in_data, in_data_len); if (rc != CKR_OK) return rc; rc = aes_mac_verify_final(tokdata, sess, ctx, out_data, out_data_len); return rc; } else { if (ctx->mech.pParameter) mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; else mac_len = AES_BLOCK_SIZE / 2; if (out_data_len != mac_len) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); return CKR_SIGNATURE_LEN_RANGE; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_mac(tokdata, in_data, in_data_len, key_obj, ((AES_DATA_CONTEXT *) ctx->context)->iv); object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (rc != CKR_OK) { TRACE_DEVEL("Token specific aes mac failed.\n"); return rc; } if (CRYPTO_memcmp(out_data, ((AES_DATA_CONTEXT *) ctx->context)->iv, out_data_len) == 0) return CKR_OK; return CKR_SIGNATURE_INVALID; } } CK_RV aes_mac_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len) { CK_ULONG rc; OBJECT *key_obj = NULL; AES_DATA_CONTEXT *context = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; if (!sess || !ctx) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_DATA_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total < AES_BLOCK_SIZE) { if (in_data_len > 0) memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; return CKR_OK; } else { // we have at least 1 block remain = (total % AES_BLOCK_SIZE); out_len = total - remain; rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } // copy any data left over from the previous signUpdate operation first memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = token_specific.t_aes_mac(tokdata, cipher, out_len, key_obj, context->iv); if (rc == CKR_OK) { // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } else { TRACE_DEVEL("Token specific aes mac failed.\n"); } free(cipher); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_mac_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *signature, CK_ULONG signature_len) { CK_ULONG rc; OBJECT *key_obj = NULL; CK_ULONG mac_len; AES_DATA_CONTEXT *context = NULL; if (!sess || !ctx || !signature) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_DATA_CONTEXT *) ctx->context; if (ctx->mech.pParameter) mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; else mac_len = AES_BLOCK_SIZE / 2; // there will never be more than one block in the context buffer // so the amount of output is as follows: // if less than 1 block stored, we generate one block of output (with // padding) // if no data stored, we are done (take the cipher from previous round) if (context->len > 0) { if (signature_len != mac_len) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); return CKR_SIGNATURE_LEN_RANGE; } /* padding with '00' in case case we didn't reach block size */ memset(context->data + context->len, 0x0, AES_BLOCK_SIZE - context->len); rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_mac(tokdata, context->data, AES_BLOCK_SIZE, key_obj, context->iv); object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (rc != CKR_OK) { TRACE_DEVEL("Token specific aes mac failed.\n"); return rc; } } if (CRYPTO_memcmp(signature, context->iv, signature_len) == 0) return CKR_OK; return CKR_SIGNATURE_INVALID; } CK_RV aes_cmac_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_ULONG rc; OBJECT *key_obj = NULL; CK_ULONG mac_len; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (ctx->mech.pParameter) mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; else mac_len = AES_BLOCK_SIZE; if (length_only == TRUE) { *out_data_len = mac_len; return CKR_OK; } if (*out_data_len < mac_len) { *out_data_len = mac_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_cmac(tokdata, in_data, in_data_len, key_obj, ((AES_CMAC_CONTEXT *)ctx->context)->iv, CK_TRUE, CK_TRUE, &((AES_CMAC_CONTEXT *)ctx->context)->ctx); if (rc != CKR_OK) { TRACE_DEVEL("Token specific aes cmac failed.\n"); goto done; } memcpy(out_data, ((AES_CMAC_CONTEXT *) ctx->context)->iv, mac_len); *out_data_len = mac_len; done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV aes_cmac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len) { CK_ULONG rc; OBJECT *key_obj = NULL; AES_CMAC_CONTEXT *context = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; if (!sess || !ctx) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CMAC_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total <= AES_BLOCK_SIZE) { if (in_data_len > 0) memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; return CKR_OK; } else { // we have at least 1 block remain = (total % AES_BLOCK_SIZE); if (remain == 0) remain = AES_BLOCK_SIZE; /* Keep last block in context */ out_len = total - remain; rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } // copy any data left over from the previous signUpdate operation first memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = token_specific.t_aes_cmac(tokdata, cipher, out_len, key_obj, context->iv, !context->initialized, CK_FALSE, &context->ctx); if (rc == CKR_OK) { // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; context->initialized = CK_TRUE; } else { TRACE_DEVEL("Token specific aes cmac failed.\n"); } free(cipher); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_cmac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_ULONG rc = CKR_OK; CK_ULONG mac_len; AES_CMAC_CONTEXT *context = NULL; OBJECT *key_obj = NULL; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CMAC_CONTEXT *) ctx->context; if (ctx->mech.pParameter) mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; else mac_len = AES_BLOCK_SIZE; if (length_only == TRUE) { *out_data_len = mac_len; return CKR_OK; } if (*out_data_len < mac_len) { *out_data_len = mac_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_cmac(tokdata, context->data, context->len, key_obj, context->iv, !context->initialized, CK_TRUE, &context->ctx); if (rc != CKR_OK) { TRACE_DEVEL("Token Specific aes cmac failed.\n"); goto done; } memcpy(out_data, context->iv, mac_len); *out_data_len = mac_len; done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV aes_cmac_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_ULONG rc; OBJECT *key_obj = NULL; CK_ULONG mac_len; if (!sess || !ctx || !in_data || !out_data) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (ctx->mech.pParameter) mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; else mac_len = AES_BLOCK_SIZE; if (out_data_len != mac_len) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); return CKR_SIGNATURE_LEN_RANGE; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_cmac(tokdata, in_data, in_data_len, key_obj, ((AES_CMAC_CONTEXT *) ctx->context)->iv, CK_TRUE, CK_TRUE, &((AES_CMAC_CONTEXT *)ctx->context)->ctx); object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (rc != CKR_OK) { TRACE_DEVEL("Token specific aes cmac failed.\n"); return rc; } if (CRYPTO_memcmp(out_data, ((AES_CMAC_CONTEXT *) ctx->context)->iv, out_data_len) == 0) { return CKR_OK; } return CKR_SIGNATURE_INVALID; } CK_RV aes_cmac_verify_update(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len) { CK_ULONG rc; OBJECT *key_obj = NULL; AES_CMAC_CONTEXT *context = NULL; CK_BYTE *cipher = NULL; CK_ULONG total, remain, out_len; if (!sess || !ctx) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CMAC_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (total <= AES_BLOCK_SIZE) { if (in_data_len > 0) memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; return CKR_OK; } else { // we have at least 1 block remain = (total % AES_BLOCK_SIZE); if (remain == 0) remain = AES_BLOCK_SIZE; /* Keep last block in context */ out_len = total - remain; rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } cipher = (CK_BYTE *) malloc(out_len); if (!cipher) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } // copy any data left over from the previous signUpdate operation first memcpy(cipher, context->data, context->len); memcpy(cipher + context->len, in_data, out_len - context->len); rc = token_specific.t_aes_cmac(tokdata, cipher, out_len, key_obj, context->iv, !context->initialized, CK_FALSE, &context->ctx); if (rc == CKR_OK) { // copy the remaining 'new' input data to the context buffer if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; context->initialized = CK_TRUE; } else { TRACE_DEVEL("Token specific aes cmac failed.\n"); } free(cipher); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } } CK_RV aes_cmac_verify_final(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *signature, CK_ULONG signature_len) { CK_ULONG rc; OBJECT *key_obj = NULL; CK_ULONG mac_len; AES_CMAC_CONTEXT *context = NULL; if (!sess || !ctx || !signature) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_CMAC_CONTEXT *) ctx->context; if (ctx->mech.pParameter) mac_len = *(CK_MAC_GENERAL_PARAMS *) ctx->mech.pParameter; else mac_len = AES_BLOCK_SIZE; if (signature_len != mac_len) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE)); return CKR_SIGNATURE_LEN_RANGE; } rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } rc = token_specific.t_aes_cmac(tokdata, context->data, context->len, key_obj, context->iv, !context->initialized, CK_TRUE, &context->ctx); object_put(tokdata, key_obj, TRUE); key_obj = NULL; if (rc != CKR_OK) { TRACE_DEVEL("Token specific aes mac failed.\n"); return rc; } if (CRYPTO_memcmp(signature, context->iv, signature_len) == 0) return CKR_OK; return CKR_SIGNATURE_INVALID; } CK_RV aes_gcm_init(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_BYTE direction) { if (token_specific.t_aes_gcm_init == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } return token_specific.t_aes_gcm_init(tokdata, sess, ctx, mech, key, direction); } CK_RV aes_gcm_encrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_RV rc; CK_GCM_PARAMS *aesgcm = NULL; CK_ULONG tag_data_len; if (!sess || !ctx || !in_data || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } aesgcm = (CK_GCM_PARAMS *) ctx->mech.pParameter; tag_data_len = (aesgcm->ulTagBits + 7) / 8; /* round to full byte */ if (length_only == TRUE) { *out_data_len = in_data_len + tag_data_len; return CKR_OK; } if (*out_data_len < in_data_len + tag_data_len) { *out_data_len = in_data_len + tag_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (token_specific.t_aes_gcm == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_gcm(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, 1); if (rc != CKR_OK) TRACE_ERROR("Token specific aes gcm encrypt failed: %02lx\n", rc); return rc; } CK_RV aes_gcm_encrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_GCM_CONTEXT *context = NULL; CK_ULONG total, remain, out_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_GCM_CONTEXT *) ctx->context; total = (context->len + in_data_len); if (length_only) { if (total < AES_BLOCK_SIZE) { *out_data_len = 0; return CKR_OK; } else { remain = (total % AES_BLOCK_SIZE); out_len = total - remain; *out_data_len = out_len; TRACE_DEVEL("Length Only requested (%02ld bytes).\n", *out_data_len); return CKR_OK; } } if (token_specific.t_aes_gcm_update == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_gcm_update(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, 1); if (rc != CKR_OK) TRACE_ERROR("Token specific AES GCM EncryptUpdate failed: %02lx\n", rc); return rc; } CK_RV aes_gcm_encrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_GCM_PARAMS *aesgcm = NULL; AES_GCM_CONTEXT *context = NULL; CK_ULONG tag_data_len; CK_RV rc = CKR_OK; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_GCM_CONTEXT *) ctx->context; aesgcm = (CK_GCM_PARAMS *) ctx->mech.pParameter; tag_data_len = (aesgcm->ulTagBits + 7) / 8; /* round to full byte */ if (length_only) { if (context->len == 0) { *out_data_len = tag_data_len; } else { *out_data_len = context->len + tag_data_len; } return CKR_OK; } if (*out_data_len < context->len + tag_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (token_specific.t_aes_gcm_final == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_gcm_final(tokdata, sess, ctx, out_data, out_data_len, 1); if (rc != CKR_OK) TRACE_ERROR("Token specific AES GCM EncryptFinal failed: " "%02lx\n", rc); return rc; } CK_RV aes_gcm_decrypt(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { CK_GCM_PARAMS *aesgcm = NULL; CK_ULONG tag_data_len; CK_RV rc; if (!sess || !ctx || !in_data || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } aesgcm = (CK_GCM_PARAMS *) ctx->mech.pParameter; tag_data_len = (aesgcm->ulTagBits + 7) / 8; /* round to full byte */ if (length_only == TRUE) { *out_data_len = in_data_len - tag_data_len; return CKR_OK; } if (*out_data_len < in_data_len - tag_data_len) { *out_data_len = in_data_len - tag_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (token_specific.t_aes_gcm == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_gcm(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, 0); if (rc != CKR_OK) TRACE_ERROR("Token specific aes gcm decrypt failed.\n"); return rc; } CK_RV aes_gcm_decrypt_update(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_GCM_CONTEXT *context = NULL; CK_GCM_PARAMS *aesgcm = NULL; CK_ULONG total, remain, out_len; CK_ULONG tag_data_len; CK_RV rc; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } /* Be aware that this part of incoming data could be the last chunk, * that means it's tag data, not encrypted plaintext. * Hence we'll keep at least tag data size in the context buffer */ context = (AES_GCM_CONTEXT *) ctx->context; total = (context->len + in_data_len); aesgcm = (CK_GCM_PARAMS *) ctx->mech.pParameter; tag_data_len = (aesgcm->ulTagBits + 7) / 8; /* round to full byte */ if (length_only) { if (total < AES_BLOCK_SIZE + tag_data_len) { *out_data_len = 0; return CKR_OK; } else { remain = ((total - tag_data_len) % AES_BLOCK_SIZE) + tag_data_len; out_len = total - remain; *out_data_len = out_len; TRACE_DEVEL("Length Only requested (%02ld bytes).\n", *out_data_len); return CKR_OK; } } if (token_specific.t_aes_gcm_update == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_gcm_update(tokdata, sess, ctx, in_data, in_data_len, out_data, out_data_len, 0); if (rc != CKR_OK) TRACE_ERROR("Token specific AES GCM DecryptUpdate failed: %02lx\n", rc); return rc; } CK_RV aes_gcm_decrypt_final(STDLL_TokData_t *tokdata, SESSION *sess, CK_BBOOL length_only, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { AES_GCM_CONTEXT *context = NULL; CK_RV rc = CKR_OK; if (!sess || !ctx || !out_data_len) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } context = (AES_GCM_CONTEXT *) ctx->context; if (length_only) { if (context->len == 0) { *out_data_len = 0; } else { *out_data_len = context->len; } return CKR_OK; } if (token_specific.t_aes_gcm_final == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_gcm_final(tokdata, sess, ctx, out_data, out_data_len, 0); if (rc != CKR_OK) TRACE_ERROR("Token specific AES GCM DecryptFinal failed: %02lx\n", rc); return rc; } // // mechanisms // // // CK_RV ckm_aes_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl) { CK_ATTRIBUTE *opaque_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_ATTRIBUTE *key_type_attr = NULL; CK_ATTRIBUTE *class_attr = NULL; CK_ATTRIBUTE *local_attr = NULL; CK_ATTRIBUTE *val_len_attr = NULL; CK_BYTE *aes_key = NULL; CK_ULONG rc; CK_ULONG key_size; CK_ULONG token_keysize; CK_BBOOL found = FALSE; CK_BBOOL is_opaque = FALSE; found = template_attribute_find(tmpl, CKA_VALUE_LEN, &val_len_attr); if (found == FALSE) return CKR_TEMPLATE_INCONSISTENT; key_size = *(CK_ULONG *) val_len_attr->pValue; if (key_size != AES_KEY_SIZE_128 && key_size != AES_KEY_SIZE_192 && key_size != AES_KEY_SIZE_256) { return CKR_ATTRIBUTE_VALUE_INVALID; } if (token_specific.t_aes_key_gen == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_key_gen(tokdata, &aes_key, &token_keysize, key_size, &is_opaque); if (rc != CKR_OK) goto err; /* For opaque keys put in CKA_IBM_OPAQUE and put dummy_key in CKA_VALUE. */ if (is_opaque) { opaque_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + token_keysize); if (!opaque_attr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto err; } opaque_attr->type = CKA_IBM_OPAQUE; opaque_attr->ulValueLen = token_keysize; opaque_attr->pValue = (CK_BYTE *) opaque_attr + sizeof(CK_ATTRIBUTE); memcpy(opaque_attr->pValue, aes_key, token_keysize); template_update_attribute(tmpl, opaque_attr); } else { if (token_keysize != key_size) { TRACE_ERROR("Invalid key size: %lu\n", token_keysize); rc = CKR_FUNCTION_FAILED; goto err; } } value_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + key_size); key_type_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE)); class_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS)); local_attr = (CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL)); if (!value_attr || !key_type_attr || !class_attr || !local_attr) { if (value_attr) free(value_attr); if (key_type_attr) free(key_type_attr); if (class_attr) free(class_attr); if (local_attr) free(local_attr); TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto err; } value_attr->type = CKA_VALUE; value_attr->ulValueLen = key_size; value_attr->pValue = (CK_BYTE *) value_attr + sizeof(CK_ATTRIBUTE); if (is_opaque) memset(value_attr->pValue, 0, key_size); else memcpy(value_attr->pValue, aes_key, key_size); free(aes_key); key_type_attr->type = CKA_KEY_TYPE; key_type_attr->ulValueLen = sizeof(CK_KEY_TYPE); key_type_attr->pValue = (CK_BYTE *) key_type_attr + sizeof(CK_ATTRIBUTE); *(CK_KEY_TYPE *) key_type_attr->pValue = CKK_AES; class_attr->type = CKA_CLASS; class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS); class_attr->pValue = (CK_BYTE *) class_attr + sizeof(CK_ATTRIBUTE); *(CK_OBJECT_CLASS *) class_attr->pValue = CKO_SECRET_KEY; local_attr->type = CKA_LOCAL; local_attr->ulValueLen = sizeof(CK_BBOOL); local_attr->pValue = (CK_BYTE *) local_attr + sizeof(CK_ATTRIBUTE); *(CK_BBOOL *) local_attr->pValue = TRUE; template_update_attribute(tmpl, value_attr); template_update_attribute(tmpl, key_type_attr); template_update_attribute(tmpl, class_attr); template_update_attribute(tmpl, local_attr); return CKR_OK; err: if (aes_key) free(aes_key); return rc; } // // CK_RV ckm_aes_ecb_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) { CK_ULONG rc; if (!in_data || !out_data || !key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (*out_data_len < in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (token_specific.t_aes_ecb == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, 1); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes ecb encrypt failed.\n"); return rc; } // // CK_RV ckm_aes_ecb_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) { CK_ULONG rc; if (!in_data || !out_data || !key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (*out_data_len < in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (token_specific.t_aes_ecb == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_ecb(tokdata, in_data, in_data_len, out_data, out_data_len, key, 0); if (rc != CKR_OK) TRACE_DEVEL("token specific aes ecb decrypt failed.\n"); return rc; } // // CK_RV ckm_aes_cbc_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *init_v, OBJECT *key) { CK_ULONG rc; if (!in_data || !out_data || !init_v || !key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (*out_data_len < in_data_len) { *out_data_len = in_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (token_specific.t_aes_cbc == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, 1); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes cbc encrypt failed.\n"); return rc; } // // CK_RV ckm_aes_cbc_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *init_v, OBJECT *key) { CK_ULONG rc; if (!in_data || !out_data || !init_v || !key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (*out_data_len < in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (token_specific.t_aes_cbc == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_cbc(tokdata, in_data, in_data_len, out_data, out_data_len, key, init_v, 0); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes cbc decrypt failed.\n"); return rc; } // // CK_RV ckm_aes_ctr_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *counterblock, CK_ULONG counter_width, OBJECT *key) { CK_ULONG rc; if (!in_data || !out_data || !counterblock || !key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (*out_data_len < in_data_len) { *out_data_len = in_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (counter_width % 8 != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (token_specific.t_aes_ctr == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_ctr(tokdata, in_data, in_data_len, out_data, out_data_len, key, counterblock, counter_width, 1); if (rc != CKR_OK) TRACE_DEVEL("Token specific aes ctr encrypt failed.\n"); return rc; } // // CK_RV ckm_aes_ctr_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *counterblock, CK_ULONG counter_width, OBJECT *key) { CK_ULONG rc; if (!in_data || !out_data || !counterblock || !key) { TRACE_ERROR("%s received bad argument(s)\n", __func__); return CKR_FUNCTION_FAILED; } if (*out_data_len < in_data_len) { *out_data_len = in_data_len; TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL)); return CKR_BUFFER_TOO_SMALL; } if (counter_width % 8 != 0) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); return CKR_MECHANISM_PARAM_INVALID; } if (token_specific.t_aes_ctr == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID)); return CKR_MECHANISM_INVALID; } rc = token_specific.t_aes_ctr(tokdata, in_data, in_data_len, out_data, out_data_len, key, counterblock, counter_width, 0); if (rc != CKR_OK) TRACE_ERROR("Token specific aes ctr decrypt failed.\n"); return rc; } // // CK_RV ckm_aes_wrap_format(STDLL_TokData_t *tokdata, CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len) { CK_BYTE *ptr = NULL; CK_ULONG len1, len2; UNUSED(tokdata); len1 = *data_len; if (*data == NULL) len1 = 0; // if the input key data isn't a multiple of the blocksize, // we pad with NULLs to the next blocksize multiple. // if (len1 % AES_BLOCK_SIZE != 0) { len2 = AES_BLOCK_SIZE * ((len1 / AES_BLOCK_SIZE) + 1); if (length_only == FALSE) { /* * Don't use realloc here, since the buffer contains a key and the * old buffer needs to be cleansed before it is freed. */ ptr = (CK_BYTE *)malloc(len2); if (!ptr) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memset(ptr + len1, 0x0, (len2 - len1)); if (*data != NULL) { memcpy(ptr, *data, len1); OPENSSL_cleanse(*data, len1); free(*data); } *data = ptr; *data_len = len2; } } return CKR_OK; }