/* * The Initial Developer of the Original Code is International * Business Machines Corporation. Portions created by IBM * Corporation are Copyright (C) 2005 International Business * Machines Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the Common Public License as published by * IBM Corporation; either version 1 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Common Public License for more details. * * You should have received a copy of the Common Public License * along with this program; if not, a copy can be viewed at * http://www.opensource.org/licenses/cpl1.0.php. */ /* (C) COPYRIGHT International Business Machines Corp. 2001, 2002, 2005 */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "tpmtok_int.h" CK_RV sha1_hash(SESSION *sess, CK_BBOOL length_only, DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { if (! sess || ! ctx || ! out_data_len) { return (CKR_FUNCTION_FAILED); } *out_data_len = SHA1_DIGEST_LENGTH; if (length_only == TRUE) { return (CKR_OK); } if (ctx->context.sha1ctx == NULL) return (CKR_HOST_MEMORY); SHA1Update(ctx->context.sha1ctx, in_data, in_data_len); SHA1Final(out_data, ctx->context.sha1ctx); return (CKR_OK); } CK_RV sha1_hmac_sign(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) { OBJECT * key_obj = NULL; CK_ATTRIBUTE * attr = NULL; CK_BYTE hash[SHA1_DIGEST_LENGTH]; DIGEST_CONTEXT digest_ctx; CK_MECHANISM digest_mech; CK_BYTE k_ipad[SHA1_BLOCK_SIZE]; CK_BYTE k_opad[SHA1_BLOCK_SIZE]; CK_ULONG key_bytes, hash_len, hmac_len; CK_ULONG i; CK_RV rc; if (! sess || ! ctx || ! out_data_len) { return (CKR_FUNCTION_FAILED); } if (ctx->mech.mechanism == CKM_SHA_1_HMAC_GENERAL) { hmac_len = *(CK_ULONG *)ctx->mech.pParameter; if (hmac_len == 0) { *out_data_len = 0; return (CKR_OK); } } else { hmac_len = SHA1_DIGEST_LENGTH; } *out_data_len = hmac_len; if (length_only == TRUE) { return (CKR_OK); } (void) memset(&digest_ctx, 0x0, sizeof (DIGEST_CONTEXT)); rc = object_mgr_find_in_map1(sess->hContext, ctx->key, &key_obj); if (rc != CKR_OK) { return (rc); } rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); if (rc == FALSE) { return (CKR_FUNCTION_FAILED); } else key_bytes = attr->ulValueLen; if (key_bytes > SHA1_BLOCK_SIZE) { digest_mech.mechanism = CKM_SHA_1; digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; rc = digest_mgr_init(sess, &digest_ctx, &digest_mech); if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } hash_len = sizeof (hash); rc = digest_mgr_digest(sess, FALSE, &digest_ctx, attr->pValue, attr->ulValueLen, hash, &hash_len); if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } (void) digest_mgr_cleanup(&digest_ctx); (void) memset(&digest_ctx, 0x0, sizeof (DIGEST_CONTEXT)); for (i = 0; i < hash_len; i++) { k_ipad[i] = hash[i] ^ 0x36; k_opad[i] = hash[i] ^ 0x5C; } (void) memset(&k_ipad[i], 0x36, SHA1_BLOCK_SIZE - i); (void) memset(&k_opad[i], 0x5C, SHA1_BLOCK_SIZE - i); } else { CK_BYTE *key = attr->pValue; for (i = 0; i < key_bytes; i++) { k_ipad[i] = key[i] ^ 0x36; k_opad[i] = key[i] ^ 0x5C; } (void) memset(&k_ipad[i], 0x36, SHA1_BLOCK_SIZE - key_bytes); (void) memset(&k_opad[i], 0x5C, SHA1_BLOCK_SIZE - key_bytes); } digest_mech.mechanism = CKM_SHA_1; digest_mech.ulParameterLen = 0; digest_mech.pParameter = NULL; if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } rc = digest_mgr_digest_update(sess, &digest_ctx, k_ipad, SHA1_BLOCK_SIZE); if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } rc = digest_mgr_digest_update(sess, &digest_ctx, in_data, in_data_len); if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } hash_len = sizeof (hash); rc = digest_mgr_digest_final(sess, &digest_ctx, hash, &hash_len); if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } (void) digest_mgr_cleanup(&digest_ctx); (void) memset(&digest_ctx, 0x0, sizeof (DIGEST_CONTEXT)); rc = digest_mgr_init(sess, &digest_ctx, &digest_mech); if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } rc = digest_mgr_digest_update(sess, &digest_ctx, k_opad, SHA1_BLOCK_SIZE); if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } rc = digest_mgr_digest_update(sess, &digest_ctx, hash, hash_len); if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } hash_len = sizeof (hash); rc = digest_mgr_digest_final(sess, &digest_ctx, hash, &hash_len); if (rc != CKR_OK) { (void) digest_mgr_cleanup(&digest_ctx); return (rc); } (void) memcpy(out_data, hash, hmac_len); *out_data_len = hmac_len; (void) digest_mgr_cleanup(&digest_ctx); return (CKR_OK); } CK_RV sha1_hmac_verify(SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG sig_len) { CK_BYTE hmac[SHA1_DIGEST_LENGTH]; SIGN_VERIFY_CONTEXT hmac_ctx; CK_ULONG hmac_len, len; CK_RV rc; if (! sess || ! ctx || ! in_data || ! signature) { return (CKR_FUNCTION_FAILED); } if (ctx->mech.mechanism == CKM_SHA_1_HMAC_GENERAL) hmac_len = *(CK_ULONG *)ctx->mech.pParameter; else hmac_len = SHA1_DIGEST_LENGTH; (void) memset(&hmac_ctx, 0, sizeof (SIGN_VERIFY_CONTEXT)); rc = sign_mgr_init(sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key); if (rc != CKR_OK) { goto done; } len = sizeof (hmac); rc = sign_mgr_sign(sess, FALSE, &hmac_ctx, in_data, in_data_len, hmac, &len); if (rc != CKR_OK) { goto done; } if ((len != hmac_len) || (len != sig_len)) { rc = CKR_SIGNATURE_LEN_RANGE; goto done; } if (memcmp(hmac, signature, hmac_len) != 0) { rc = CKR_SIGNATURE_INVALID; } done: (void) sign_mgr_cleanup(&hmac_ctx); return (rc); }