| |
| /* |
| * 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 */ |
| |
| |
| // File: mech_rsa.c |
| // |
| // Mechanisms for RSA |
| // |
| // Routines contained within: |
| |
| #include <pthread.h> |
| #include <stdio.h> |
| |
| #include <string.h> // for memcmp() et al |
| #include <stdlib.h> |
| |
| #include "pkcs11/pkcs11types.h" |
| #include <pkcs11/stdll.h> |
| #include "defs.h" |
| #include "host_defs.h" |
| #include "tok_spec_struct.h" |
| #include "h_extern.h" |
| |
| // |
| // |
| CK_RV |
| ckm_rsa_key_pair_gen( TEMPLATE * publ_tmpl, |
| TEMPLATE * priv_tmpl ) |
| { |
| CK_RV rc; |
| |
| rc = token_specific.t_rsa_generate_keypair(publ_tmpl, priv_tmpl); |
| if (rc != CKR_OK) |
| st_err_log(91, __FILE__, __LINE__); |
| |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| ckm_rsa_encrypt( CK_BYTE * in_data, |
| CK_ULONG in_data_len, |
| CK_BYTE * out_data, |
| CK_ULONG * out_data_len, |
| OBJECT * key_obj ) |
| { |
| CK_ATTRIBUTE * attr = NULL; |
| CK_ATTRIBUTE * modulus = NULL; |
| CK_OBJECT_CLASS keyclass; |
| CK_RV rc; |
| |
| |
| rc = template_attribute_find( key_obj->template, CKA_CLASS, &attr ); |
| if (rc == FALSE){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| else |
| keyclass = *(CK_OBJECT_CLASS *)attr->pValue; |
| |
| // this had better be a public key |
| // |
| if (keyclass != CKO_PUBLIC_KEY){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| |
| rc = token_specific.t_rsa_encrypt(in_data, in_data_len, out_data, out_data_len, key_obj); |
| if (rc != CKR_OK) |
| st_err_log(134, __FILE__, __LINE__); |
| |
| return rc; |
| } |
| |
| // |
| // |
| CK_RV |
| ckm_rsa_decrypt( CK_BYTE * in_data, |
| CK_ULONG in_data_len, |
| CK_BYTE * out_data, |
| CK_ULONG * out_data_len, |
| OBJECT * key_obj ) |
| { |
| CK_ATTRIBUTE * attr = NULL; |
| CK_OBJECT_CLASS keyclass; |
| CK_RV rc; |
| |
| |
| rc = template_attribute_find( key_obj->template, CKA_CLASS, &attr ); |
| if (rc == FALSE){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| else |
| keyclass = *(CK_OBJECT_CLASS *)attr->pValue; |
| |
| // this had better be a private key |
| // |
| if (keyclass != CKO_PRIVATE_KEY){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| rc = token_specific.t_rsa_decrypt(in_data, in_data_len, out_data, out_data_len, key_obj); |
| if (rc != CKR_OK) |
| st_err_log(135, __FILE__, __LINE__); |
| |
| return rc; |
| } |
| |
| // |
| // |
| CK_RV |
| ckm_rsa_sign( CK_BYTE * in_data, |
| CK_ULONG in_data_len, |
| CK_BYTE * out_data, |
| CK_ULONG * out_data_len, |
| OBJECT * key_obj ) |
| { |
| CK_ATTRIBUTE * attr = NULL; |
| CK_OBJECT_CLASS keyclass; |
| CK_RV rc; |
| |
| |
| rc = template_attribute_find( key_obj->template, CKA_CLASS, &attr ); |
| if (rc == FALSE){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| else |
| keyclass = *(CK_OBJECT_CLASS *)attr->pValue; |
| |
| // this had better be a private key |
| // |
| if (keyclass != CKO_PRIVATE_KEY){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| rc = token_specific.t_rsa_sign(in_data, in_data_len, out_data, out_data_len, key_obj); |
| if (rc != CKR_OK) |
| st_err_log(135, __FILE__, __LINE__); |
| |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| ckm_rsa_verify( CK_BYTE * in_data, |
| CK_ULONG in_data_len, |
| CK_BYTE * out_data, |
| CK_ULONG out_data_len, |
| OBJECT * key_obj ) |
| { |
| CK_ATTRIBUTE * attr = NULL; |
| CK_OBJECT_CLASS keyclass; |
| CK_RV rc; |
| |
| |
| rc = template_attribute_find( key_obj->template, CKA_CLASS, &attr ); |
| if (rc == FALSE){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| else |
| keyclass = *(CK_OBJECT_CLASS *)attr->pValue; |
| |
| // this had better be a private key |
| // |
| if (keyclass != CKO_PUBLIC_KEY){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| rc = token_specific.t_rsa_verify(in_data, in_data_len, out_data, out_data_len, key_obj); |
| if (rc != CKR_OK) |
| st_err_log(135, __FILE__, __LINE__); |
| |
| return rc; |
| } |
| // |
| // |
| CK_RV |
| rsa_pkcs_encrypt( 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_obj = NULL; |
| CK_ATTRIBUTE *attr = NULL; |
| CK_BYTE clear[256], cipher[256]; // 2048 bits |
| CK_ULONG modulus_bytes; |
| CK_BBOOL flag; |
| CK_RV rc; |
| |
| |
| rc = object_mgr_find_in_map1( ctx->key, &key_obj ); |
| if (rc != CKR_OK){ |
| st_err_log(110, __FILE__, __LINE__); |
| return rc; |
| } |
| flag = template_attribute_find( key_obj->template, CKA_MODULUS, &attr ); |
| if (flag == FALSE){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| else |
| modulus_bytes = attr->ulValueLen; |
| |
| // check input data length restrictions |
| // |
| if (in_data_len > (modulus_bytes - 11)){ |
| st_err_log(109, __FILE__, __LINE__); |
| return CKR_DATA_LEN_RANGE; |
| } |
| |
| if (length_only == TRUE) { |
| *out_data_len = modulus_bytes; |
| return CKR_OK; |
| } |
| |
| if (*out_data_len < modulus_bytes) { |
| *out_data_len = modulus_bytes; |
| st_err_log(111, __FILE__, __LINE__); |
| return CKR_BUFFER_TOO_SMALL; |
| } |
| |
| rc = ckm_rsa_encrypt( in_data, in_data_len, out_data, out_data_len, key_obj ); |
| if (rc != CKR_OK) |
| st_err_log(132, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| rsa_pkcs_decrypt( 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_obj = NULL; |
| CK_ATTRIBUTE *attr = NULL; |
| CK_ULONG i, modulus_bytes; |
| CK_BBOOL flag; |
| CK_RV rc; |
| |
| |
| rc = object_mgr_find_in_map1( ctx->key, &key_obj ); |
| if (rc != CKR_OK){ |
| st_err_log(110, __FILE__, __LINE__); |
| return rc; |
| } |
| flag = template_attribute_find( key_obj->template, CKA_MODULUS, &attr ); |
| if (flag == FALSE) |
| return CKR_FUNCTION_FAILED; |
| else |
| modulus_bytes = attr->ulValueLen; |
| |
| // check input data length restrictions |
| // |
| if (in_data_len != modulus_bytes){ |
| st_err_log(112, __FILE__, __LINE__); |
| return CKR_ENCRYPTED_DATA_LEN_RANGE; |
| } |
| if (length_only == TRUE) { |
| // this is not exact but it's the upper bound; otherwise we'll need |
| // to do the RSA operation just to get the required length |
| // |
| *out_data_len = modulus_bytes - 11; |
| return CKR_OK; |
| } |
| |
| rc = ckm_rsa_decrypt( in_data, modulus_bytes, out_data, out_data_len, key_obj ); |
| if (rc != CKR_OK) |
| st_err_log(133, __FILE__, __LINE__); |
| |
| if (rc == CKR_DATA_LEN_RANGE){ |
| st_err_log(109, __FILE__, __LINE__); |
| return CKR_ENCRYPTED_DATA_LEN_RANGE; |
| } |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| rsa_pkcs_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 data[256], sig[256]; // max size: 256 bytes == 2048 bits |
| CK_ULONG modulus_bytes; |
| CK_BBOOL flag; |
| CK_RV rc; |
| |
| |
| if (!sess || !ctx || !out_data_len){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| rc = object_mgr_find_in_map1( ctx->key, &key_obj ); |
| if (rc != CKR_OK){ |
| st_err_log(110, __FILE__, __LINE__); |
| return rc; |
| } |
| flag = template_attribute_find( key_obj->template, CKA_MODULUS, &attr ); |
| if (flag == FALSE) |
| return CKR_FUNCTION_FAILED; |
| else |
| modulus_bytes = attr->ulValueLen; |
| |
| // check input data length restrictions |
| // |
| #if 0 |
| if (in_data_len != modulus_bytes){ |
| st_err_log(109, __FILE__, __LINE__); |
| return CKR_DATA_LEN_RANGE; |
| } |
| #endif |
| if (in_data_len > modulus_bytes - 11){ |
| st_err_log(109, __FILE__, __LINE__); |
| return CKR_DATA_LEN_RANGE; |
| } |
| if (length_only == TRUE) { |
| *out_data_len = modulus_bytes; |
| return CKR_OK; |
| } |
| |
| if (*out_data_len < modulus_bytes) { |
| *out_data_len = modulus_bytes; |
| st_err_log(111, __FILE__, __LINE__); |
| return CKR_BUFFER_TOO_SMALL; |
| } |
| |
| #if 0 |
| // signing is a private key operation --> decrypt |
| // |
| rc = ckm_rsa_decrypt( data, in_data_len, out_data, out_data_len, key_obj ); |
| #else |
| rc = ckm_rsa_sign( in_data, in_data_len, out_data, out_data_len, key_obj ); |
| #endif |
| if (rc != CKR_OK) |
| st_err_log(133, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| rsa_pkcs_verify( SESSION * sess, |
| SIGN_VERIFY_CONTEXT * ctx, |
| CK_BYTE * in_data, |
| CK_ULONG in_data_len, |
| CK_BYTE * signature, |
| CK_ULONG sig_len ) |
| { |
| OBJECT *key_obj = NULL; |
| CK_ATTRIBUTE *attr = NULL; |
| CK_BYTE out[256]; // 2048 bits |
| CK_ULONG i, modulus_bytes, out_len = 256; |
| CK_BBOOL flag; |
| CK_RV rc; |
| |
| |
| rc = object_mgr_find_in_map1( ctx->key, &key_obj ); |
| if (rc != CKR_OK){ |
| st_err_log(110, __FILE__, __LINE__); |
| return rc; |
| } |
| flag = template_attribute_find( key_obj->template, CKA_MODULUS, &attr ); |
| if (flag == FALSE){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| else |
| modulus_bytes = attr->ulValueLen; |
| |
| // check input data length restrictions |
| // |
| if (sig_len != modulus_bytes){ |
| st_err_log(46, __FILE__, __LINE__); |
| return CKR_SIGNATURE_LEN_RANGE; |
| } |
| // verify is a public key operation --> encrypt |
| // |
| #if 0 |
| rc = ckm_rsa_encrypt( signature, modulus_bytes, out, &out_len, key_obj ); |
| if (rc == CKR_OK) { |
| if (out_len != in_data_len){ |
| st_err_log(47, __FILE__, __LINE__); |
| return CKR_SIGNATURE_INVALID; |
| } |
| |
| if (memcmp(in_data, &out, out_len) != 0){ |
| st_err_log(47, __FILE__, __LINE__); |
| return CKR_SIGNATURE_INVALID; |
| } |
| return CKR_OK; |
| } |
| else |
| #else |
| rc = ckm_rsa_verify( in_data, in_data_len, signature, sig_len, key_obj ); |
| if (rc != CKR_OK) |
| #endif |
| st_err_log(132, __FILE__, __LINE__); |
| |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| rsa_pkcs_verify_recover( SESSION * sess, |
| CK_BBOOL length_only, |
| SIGN_VERIFY_CONTEXT * ctx, |
| CK_BYTE * signature, |
| CK_ULONG sig_len, |
| CK_BYTE * out_data, |
| CK_ULONG * out_data_len ) |
| { |
| OBJECT *key_obj = NULL; |
| CK_ATTRIBUTE *attr = NULL; |
| CK_ULONG i, modulus_bytes; |
| CK_BBOOL flag; |
| CK_RV rc; |
| |
| |
| if (!sess || !ctx || !out_data_len){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| rc = object_mgr_find_in_map1( ctx->key, &key_obj ); |
| if (rc != CKR_OK){ |
| st_err_log(110, __FILE__, __LINE__); |
| return rc; |
| } |
| flag = template_attribute_find( key_obj->template, CKA_MODULUS, &attr ); |
| if (flag == FALSE){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| else |
| modulus_bytes = attr->ulValueLen; |
| |
| // check input data length restrictions |
| // |
| if (sig_len != modulus_bytes){ |
| st_err_log(46, __FILE__, __LINE__); |
| return CKR_SIGNATURE_LEN_RANGE; |
| } |
| if (length_only == TRUE) { |
| *out_data_len = modulus_bytes; |
| return CKR_OK; |
| } |
| |
| // verify is a public key operation --> encrypt |
| // |
| rc = ckm_rsa_encrypt( signature, modulus_bytes, out_data, out_data_len, key_obj ); |
| if (rc != CKR_OK) |
| st_err_log(132, __FILE__, __LINE__); |
| |
| return rc; |
| } |
| |
| // |
| // |
| CK_RV |
| rsa_hash_pkcs_sign( SESSION * sess, |
| CK_BBOOL length_only, |
| SIGN_VERIFY_CONTEXT * ctx, |
| CK_BYTE * in_data, |
| CK_ULONG in_data_len, |
| CK_BYTE * signature, |
| CK_ULONG * sig_len ) |
| { |
| CK_BYTE * ber_data = NULL; |
| CK_BYTE * octet_str = NULL; |
| CK_BYTE * oid = NULL; |
| CK_BYTE * tmp = NULL; |
| |
| CK_ULONG buf1[16]; // 64 bytes is more than enough |
| |
| CK_BYTE hash[SHA1_HASH_SIZE]; // big enough for SHA1, MD5 or MD2 |
| DIGEST_CONTEXT digest_ctx; |
| SIGN_VERIFY_CONTEXT sign_ctx; |
| CK_MECHANISM digest_mech; |
| CK_MECHANISM sign_mech; |
| CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len; |
| CK_RV rc; |
| |
| if (!sess || !ctx || !in_data){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| memset( &digest_ctx, 0x0, sizeof(digest_ctx) ); |
| memset( &sign_ctx, 0x0, sizeof(sign_ctx) ); |
| |
| if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) { |
| digest_mech.mechanism = CKM_MD2; |
| oid = ber_AlgMd2; |
| oid_len = ber_AlgMd2Len; |
| |
| } |
| else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) { |
| digest_mech.mechanism = CKM_MD5; |
| oid = ber_AlgMd5; |
| oid_len = ber_AlgMd5Len; |
| } |
| else { |
| digest_mech.mechanism = CKM_SHA_1; |
| oid = ber_AlgSha1; |
| oid_len = ber_AlgSha1Len; |
| } |
| |
| digest_mech.ulParameterLen = 0; |
| digest_mech.pParameter = NULL; |
| |
| rc = digest_mgr_init( sess, &digest_ctx, &digest_mech ); |
| if (rc != CKR_OK){ |
| st_err_log(123, __FILE__, __LINE__); |
| goto error; |
| } |
| hash_len = sizeof(hash); |
| rc = digest_mgr_digest( sess, length_only, &digest_ctx, in_data, in_data_len, hash, &hash_len ); |
| if (rc != CKR_OK){ |
| st_err_log(124, __FILE__, __LINE__); |
| goto error; |
| } |
| // build the BER-encodings |
| |
| rc = ber_encode_OCTET_STRING( FALSE, &octet_str, &octet_str_len, hash, hash_len ); |
| if (rc != CKR_OK){ |
| st_err_log(77, __FILE__, __LINE__); |
| goto error; |
| } |
| tmp = (CK_BYTE *)buf1; |
| memcpy( tmp, oid, oid_len ); |
| memcpy( tmp + oid_len, octet_str, octet_str_len); |
| |
| rc = ber_encode_SEQUENCE( FALSE, &ber_data, &ber_data_len, tmp, (oid_len + octet_str_len) ); |
| if (rc != CKR_OK){ |
| st_err_log(78, __FILE__, __LINE__); |
| goto error; |
| } |
| // sign the BER-encoded data block |
| |
| |
| sign_mech.mechanism = CKM_RSA_PKCS; |
| sign_mech.ulParameterLen = 0; |
| sign_mech.pParameter = NULL; |
| |
| rc = sign_mgr_init( sess, &sign_ctx, &sign_mech, FALSE, ctx->key ); |
| if (rc != CKR_OK){ |
| st_err_log(127, __FILE__, __LINE__); |
| goto error; |
| } |
| //rc = sign_mgr_sign( sess, length_only, &sign_ctx, hash, hash_len, signature, sig_len ); |
| rc = sign_mgr_sign( sess, length_only, &sign_ctx, ber_data, ber_data_len, signature, sig_len ); |
| if (rc != CKR_OK) |
| st_err_log(128, __FILE__, __LINE__); |
| |
| error: |
| if (octet_str) free( octet_str ); |
| if (ber_data) free( ber_data ); |
| digest_mgr_cleanup( &digest_ctx ); |
| sign_mgr_cleanup( &sign_ctx ); |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| rsa_hash_pkcs_sign_update( SESSION * sess, |
| SIGN_VERIFY_CONTEXT * ctx, |
| CK_BYTE * in_data, |
| CK_ULONG in_data_len ) |
| { |
| RSA_DIGEST_CONTEXT * context = NULL; |
| CK_MECHANISM digest_mech; |
| CK_RV rc; |
| |
| if (!sess || !ctx || !in_data){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| context = (RSA_DIGEST_CONTEXT *)ctx->context; |
| |
| if (context->flag == FALSE) { |
| if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) |
| digest_mech.mechanism = CKM_MD2; |
| else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) |
| digest_mech.mechanism = CKM_MD5; |
| else |
| digest_mech.mechanism = CKM_SHA_1; |
| |
| digest_mech.ulParameterLen = 0; |
| digest_mech.pParameter = NULL; |
| |
| rc = digest_mgr_init( sess, &context->hash_context, &digest_mech ); |
| if (rc != CKR_OK){ |
| st_err_log(123, __FILE__, __LINE__); |
| goto error; |
| } |
| context->flag = TRUE; |
| } |
| |
| rc = digest_mgr_digest_update( sess, &context->hash_context, in_data, in_data_len ); |
| if (rc != CKR_OK){ |
| st_err_log(123, __FILE__, __LINE__); |
| goto error; |
| } |
| return CKR_OK; |
| |
| error: |
| digest_mgr_cleanup( &context->hash_context ); |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| rsa_hash_pkcs_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 * ber_data = NULL; |
| CK_BYTE * octet_str = NULL; |
| CK_BYTE * oid = NULL; |
| CK_BYTE * tmp = NULL; |
| |
| CK_ULONG buf1[16]; // 64 bytes is more than enough |
| CK_BYTE hash[SHA1_HASH_SIZE]; |
| DIGEST_CONTEXT digest_ctx; |
| SIGN_VERIFY_CONTEXT verify_ctx; |
| CK_MECHANISM digest_mech; |
| CK_MECHANISM verify_mech; |
| CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len; |
| CK_RV rc; |
| |
| if (!sess || !ctx || !in_data){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| memset( &digest_ctx, 0x0, sizeof(digest_ctx) ); |
| memset( &verify_ctx, 0x0, sizeof(verify_ctx) ); |
| |
| if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) { |
| digest_mech.mechanism = CKM_MD2; |
| oid = ber_AlgMd2; |
| oid_len = ber_AlgMd2Len; |
| } |
| else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) { |
| digest_mech.mechanism = CKM_MD5; |
| oid = ber_AlgMd5; |
| oid_len = ber_AlgMd5Len; |
| } |
| else { |
| digest_mech.mechanism = CKM_SHA_1; |
| oid = ber_AlgSha1; |
| oid_len = ber_AlgSha1Len; |
| } |
| |
| |
| digest_mech.ulParameterLen = 0; |
| digest_mech.pParameter = NULL; |
| |
| rc = digest_mgr_init( sess, &digest_ctx, &digest_mech ); |
| if (rc != CKR_OK){ |
| st_err_log(123, __FILE__, __LINE__); |
| goto done; |
| } |
| hash_len = sizeof(hash); |
| rc = digest_mgr_digest( sess, FALSE, &digest_ctx, in_data, in_data_len, hash, &hash_len ); |
| if (rc != CKR_OK){ |
| st_err_log(124, __FILE__, __LINE__); |
| goto done; |
| } |
| |
| // Build the BER encoding |
| // |
| rc = ber_encode_OCTET_STRING( FALSE, &octet_str, &octet_str_len, hash, hash_len ); |
| if (rc != CKR_OK){ |
| st_err_log(77, __FILE__, __LINE__); |
| goto done; |
| } |
| tmp = (CK_BYTE *)buf1; |
| memcpy( tmp, oid, oid_len ); |
| memcpy( tmp + oid_len, octet_str, octet_str_len ); |
| |
| rc = ber_encode_SEQUENCE( FALSE, &ber_data, &ber_data_len, tmp, (oid_len + octet_str_len) ); |
| if (rc != CKR_OK){ |
| st_err_log(78, __FILE__, __LINE__); |
| goto done; |
| } |
| // Verify the Signed BER-encoded Data block |
| // |
| verify_mech.mechanism = CKM_RSA_PKCS; |
| verify_mech.ulParameterLen = 0; |
| verify_mech.pParameter = NULL; |
| |
| rc = verify_mgr_init( sess, &verify_ctx, &verify_mech, FALSE, ctx->key ); |
| if (rc != CKR_OK){ |
| st_err_log(167, __FILE__, __LINE__); |
| goto done; |
| } |
| //rc = verify_mgr_verify( sess, &verify_ctx, hash, hash_len, signature, sig_len ); |
| rc = verify_mgr_verify( sess, &verify_ctx, ber_data, ber_data_len, signature, sig_len ); |
| if (rc != CKR_OK) |
| st_err_log(168, __FILE__, __LINE__); |
| done: |
| if (octet_str) free( octet_str ); |
| if (ber_data) free( ber_data ); |
| |
| digest_mgr_cleanup( &digest_ctx ); |
| sign_mgr_cleanup( &verify_ctx ); |
| return rc; |
| } |
| |
| // |
| // |
| CK_RV |
| rsa_hash_pkcs_verify_update( SESSION * sess, |
| SIGN_VERIFY_CONTEXT * ctx, |
| CK_BYTE * in_data, |
| CK_ULONG in_data_len ) |
| { |
| RSA_DIGEST_CONTEXT * context = NULL; |
| CK_MECHANISM digest_mech; |
| CK_RV rc; |
| |
| if (!sess || !ctx || !in_data){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| context = (RSA_DIGEST_CONTEXT *)ctx->context; |
| |
| if (context->flag == FALSE) { |
| if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) |
| digest_mech.mechanism = CKM_MD2; |
| else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) |
| digest_mech.mechanism = CKM_MD5; |
| else |
| digest_mech.mechanism = CKM_SHA_1; |
| |
| digest_mech.ulParameterLen = 0; |
| digest_mech.pParameter = NULL; |
| |
| rc = digest_mgr_init( sess, &context->hash_context, &digest_mech ); |
| if (rc != CKR_OK){ |
| st_err_log(123, __FILE__, __LINE__); |
| goto error; |
| } |
| context->flag = TRUE; |
| } |
| |
| rc = digest_mgr_digest_update( sess, &context->hash_context, in_data, in_data_len ); |
| if (rc != CKR_OK){ |
| st_err_log(123, __FILE__, __LINE__); |
| goto error; |
| } |
| return CKR_OK; |
| |
| error: |
| digest_mgr_cleanup( &context->hash_context ); |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| rsa_hash_pkcs_sign_final( SESSION * sess, |
| CK_BBOOL length_only, |
| SIGN_VERIFY_CONTEXT * ctx, |
| CK_BYTE * signature, |
| CK_ULONG * sig_len ) |
| { |
| CK_BYTE * ber_data = NULL; |
| CK_BYTE * octet_str = NULL; |
| CK_BYTE * oid = NULL; |
| CK_BYTE * tmp = NULL; |
| |
| CK_ULONG buf1[16]; // 64 bytes is more than enough |
| |
| CK_BYTE hash[SHA1_HASH_SIZE]; |
| RSA_DIGEST_CONTEXT * context = NULL; |
| CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len; |
| CK_MECHANISM sign_mech; |
| SIGN_VERIFY_CONTEXT sign_ctx; |
| CK_RV rc; |
| |
| if (!sess || !ctx || !sig_len){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| |
| if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) { |
| oid = ber_AlgMd2; |
| oid_len = ber_AlgMd2Len; |
| } |
| else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) { |
| oid = ber_AlgMd5; |
| oid_len = ber_AlgMd5Len; |
| } |
| else { |
| oid = ber_AlgSha1; |
| oid_len = ber_AlgSha1Len; |
| } |
| |
| memset( &sign_ctx, 0x0, sizeof(sign_ctx)); |
| |
| context = (RSA_DIGEST_CONTEXT *)ctx->context; |
| |
| hash_len = sizeof(hash); |
| rc = digest_mgr_digest_final( sess, length_only, &context->hash_context, hash, &hash_len ); |
| if (rc != CKR_OK){ |
| st_err_log(126, __FILE__, __LINE__); |
| goto done; |
| } |
| // Build the BER Encoded Data block |
| // |
| rc = ber_encode_OCTET_STRING( FALSE, &octet_str, &octet_str_len, hash, hash_len ); |
| if (rc != CKR_OK){ |
| st_err_log(77, __FILE__, __LINE__); |
| goto done; |
| } |
| tmp = (CK_BYTE *)buf1; |
| memcpy( tmp, oid, oid_len ); |
| memcpy( tmp + oid_len, octet_str, octet_str_len ); |
| |
| rc = ber_encode_SEQUENCE( FALSE, &ber_data, &ber_data_len, tmp, (oid_len + octet_str_len) ); |
| if (rc != CKR_OK){ |
| st_err_log(78, __FILE__, __LINE__); |
| goto done; |
| } |
| // sign the BER-encoded data block |
| // |
| |
| sign_mech.mechanism = CKM_RSA_PKCS; |
| sign_mech.ulParameterLen = 0; |
| sign_mech.pParameter = NULL; |
| |
| rc = sign_mgr_init( sess, &sign_ctx, &sign_mech, FALSE, ctx->key ); |
| if (rc != CKR_OK){ |
| st_err_log(127, __FILE__, __LINE__); |
| goto done; |
| } |
| //rc = sign_mgr_sign( sess, length_only, &sign_ctx, hash, hash_len, signature, sig_len ); |
| rc = sign_mgr_sign( sess, length_only, &sign_ctx, ber_data, ber_data_len, signature, sig_len ); |
| if (rc != CKR_OK) |
| st_err_log(128, __FILE__, __LINE__); |
| |
| if (length_only == TRUE || rc == CKR_BUFFER_TOO_SMALL) { |
| sign_mgr_cleanup( &sign_ctx ); |
| return rc; |
| } |
| |
| done: |
| if (octet_str) free( octet_str ); |
| if (ber_data) free( ber_data ); |
| |
| digest_mgr_cleanup( &context->hash_context ); |
| sign_mgr_cleanup( &sign_ctx ); |
| return rc; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| rsa_hash_pkcs_verify_final( SESSION * sess, |
| SIGN_VERIFY_CONTEXT * ctx, |
| CK_BYTE * signature, |
| CK_ULONG sig_len ) |
| { |
| CK_BYTE * ber_data = NULL; |
| CK_BYTE * octet_str = NULL; |
| CK_BYTE * oid = NULL; |
| CK_BYTE * tmp = NULL; |
| |
| CK_ULONG buf1[16]; // 64 bytes is more than enough |
| CK_BYTE hash[SHA1_HASH_SIZE]; |
| RSA_DIGEST_CONTEXT * context = NULL; |
| CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len; |
| CK_MECHANISM verify_mech; |
| SIGN_VERIFY_CONTEXT verify_ctx; |
| CK_RV rc; |
| |
| if (!sess || !ctx || !signature){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) { |
| oid = ber_AlgMd2; |
| oid_len = ber_AlgMd2Len; |
| } |
| else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) { |
| oid = ber_AlgMd5; |
| oid_len = ber_AlgMd5Len; |
| } |
| else { |
| oid = ber_AlgSha1; |
| oid_len = ber_AlgSha1Len; |
| } |
| |
| memset( &verify_ctx, 0x0, sizeof(verify_ctx)); |
| |
| context = (RSA_DIGEST_CONTEXT *)ctx->context; |
| |
| hash_len = sizeof(hash); |
| rc = digest_mgr_digest_final( sess, FALSE, &context->hash_context, hash, &hash_len ); |
| if (rc != CKR_OK){ |
| st_err_log(126, __FILE__, __LINE__); |
| goto done; |
| } |
| // Build the BER encoding |
| // |
| rc = ber_encode_OCTET_STRING( FALSE, &octet_str, &octet_str_len, hash, hash_len ); |
| if (rc != CKR_OK){ |
| st_err_log(77, __FILE__, __LINE__); |
| goto done; |
| } |
| tmp = (CK_BYTE *)buf1; |
| memcpy( tmp, oid, oid_len ); |
| memcpy( tmp + oid_len, octet_str, octet_str_len ); |
| |
| rc = ber_encode_SEQUENCE( FALSE, &ber_data, &ber_data_len, tmp, (oid_len + octet_str_len) ); |
| if (rc != CKR_OK){ |
| st_err_log(78, __FILE__, __LINE__); |
| goto done; |
| } |
| // verify the signed BER-encoded data block |
| // |
| |
| verify_mech.mechanism = CKM_RSA_PKCS; |
| verify_mech.ulParameterLen = 0; |
| verify_mech.pParameter = NULL; |
| |
| rc = verify_mgr_init( sess, &verify_ctx, &verify_mech, FALSE, ctx->key ); |
| if (rc != CKR_OK){ |
| st_err_log(167, __FILE__, __LINE__); |
| goto done; |
| } |
| //rc = verify_mgr_verify( sess, &verify_ctx, hash, hash_len, signature, sig_len ); |
| rc = verify_mgr_verify( sess, &verify_ctx, ber_data, ber_data_len, signature, sig_len ); |
| if (rc != CKR_OK) |
| st_err_log(168, __FILE__, __LINE__); |
| done: |
| if (octet_str) free( octet_str ); |
| if (ber_data) free( ber_data ); |
| digest_mgr_cleanup( &context->hash_context ); |
| verify_mgr_cleanup( &verify_ctx ); |
| return rc; |
| } |