/* $Id: mscrypto_rsa_sign.c,v 1.2 2005/01/30 18:45:56 rumen Exp $ */
#include <openssl/engine.h>
#include "mscrypto_err.h"
#include "mscrypto_int.h"


int/*bool*/
mscrypto_rsa_sign(
    int dtype,
    const unsigned char *m,
    unsigned int m_length,
    unsigned char *sigret,
    unsigned int *siglen,
    const RSA *rsa
) {
    int ret = 0;

    MSCRYPTO_KEYCTX *keyctx;
    HCRYPTKEY hKey;
    HCRYPTHASH hHash = (HCRYPTHASH)NULL;
    BYTE *pbSignature = NULL;
    DWORD dwSigLen;

#ifdef MSCRYPTO_TRACE
fprintf(stderr, "TRACE[mscrypto] mscrypto_rsa_sign(dtype=%d,...):\n", dtype);
#endif

    keyctx = RSA_get_ex_data(rsa, 0);
    if (keyctx == NULL) {
        MSCRYPTOerr(MSCRYPTO_F_RSA_SIGN, MSCRYPTO_R_MISSING_KEY_CONTEXT);
        goto done;
    }

    hKey = mscrypto_get_hKey(rsa, 0);
    if (hKey == (HCRYPTKEY)NULL) {
        MSCRYPTOerr(MSCRYPTO_F_RSA_SIGN, MSCRYPTO_R_KEY_IS_NOT_SET);
        goto done;
    }

    hHash = mscrypto_create_hash(keyctx->hCryptProv, dtype, m, m_length);
    if (hHash == (HCRYPTHASH)NULL) {
        /*error is already set*/
        goto done;
    }

    pbSignature = NULL;
    dwSigLen= 0;
    if (!CryptSignHash(
        hHash,
        keyctx->dwKeySpec,
        (LPCSTR ) NULL /*sDescription*/,
        (DWORD) 0 /*dwFlags*/,
        pbSignature,
        &dwSigLen
    )) {
        MSCRYPTOerr(MSCRYPTO_F_RSA_SIGN, MSCRYPTO_R_W32ERR);
        MSCRYPTOw32err("CryptSignHash get size fail");
        goto done;
    }

#ifdef MSCRYPTO_TRACE
fprintf(stderr, "TRACE[mscrypto] mscrypto_rsa_sign() dwSigLen=%d\n", (int)dwSigLen);
#endif
    pbSignature = (BYTE *) malloc(dwSigLen);
    if (pbSignature == NULL) {
        MSCRYPTOerr(MSCRYPTO_F_RSA_SIGN, MSCRYPTO_R_INSUFFICIENT_MEMORY);
        goto done;
    }
    if (!CryptSignHash(
        hHash,
        keyctx->dwKeySpec,
        (LPCSTR ) NULL /*sDescription*/,
        (DWORD) 0 /*dwFlags*/,
        pbSignature,
        &dwSigLen
    )) {
         MSCRYPTOerr(MSCRYPTO_F_RSA_SIGN, MSCRYPTO_R_W32ERR);
         MSCRYPTOw32err("CryptSignHash fail");
         goto done;
    }

    memcpy_rev(sigret, pbSignature, (size_t) dwSigLen);
    *siglen = (int) dwSigLen;
    ret = 1;

done:
    if (pbSignature) free(pbSignature);
    if (hHash) CryptDestroyHash(hHash);

#ifdef MSCRYPTO_TRACE
fprintf(stderr, "TRACE[mscrypto] mscrypto_rsa_sign()^ ret=%d\n", ret);
#endif
    return(ret);
}
