* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "app_dgst.h"
#include <limits.h>
#include <string.h>
#include "bsl_sal.h"
#include "crypt_errno.h"
#include "crypt_eal_md.h"
#include "crypt_eal_rand.h"
#include "crypt_eal_pkey.h"
#include "crypt_eal_codecs.h"
#include "bsl_errno.h"
#include "app_opt.h"
#include "app_function.h"
#include "app_list.h"
#include "app_errno.h"
#include "app_print.h"
#include "app_utils.h"
#include "app_sm.h"
#include "app_keymgmt.h"
#include "app_provider.h"
#define IS_SUPPORT_GET_EOF 1
#define MAX_CERT_KEY_SIZE (256 * 1024)
typedef enum OptionChoice {
HITLS_APP_OPT_DGST_ERR = -1,
HITLS_APP_OPT_DGST_EOF = 0,
HITLS_APP_OPT_DGST_FILE = HITLS_APP_OPT_DGST_EOF,
HITLS_APP_OPT_DGST_HELP =
1,
HITLS_APP_OPT_DGST_ALG,
HITLS_APP_OPT_DGST_OUT,
HITLS_APP_OPT_DGST_SIGN,
HITLS_APP_OPT_DGST_VERIFY,
HITLS_APP_OPT_DGST_SIGNATURE,
HITLS_APP_OPT_DGST_USERID,
HITLS_APP_PROV_ENUM,
#ifdef HITLS_APP_SM_MODE
HITLS_SM_OPTIONS_ENUM,
#endif
} HITLSOptType;
static const HITLS_CmdOption g_dgstOpts[] = {
{"help", HITLS_APP_OPT_DGST_HELP, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Display this function summary"},
{"md", HITLS_APP_OPT_DGST_ALG, HITLS_APP_OPT_VALUETYPE_STRING, "Digest algorithm"},
{"out", HITLS_APP_OPT_DGST_OUT, HITLS_APP_OPT_VALUETYPE_OUT_FILE, "Output the summary result to a file"},
{"sign", HITLS_APP_OPT_DGST_SIGN, HITLS_APP_OPT_VALUETYPE_IN_FILE, "Private key for signature"},
{"verify", HITLS_APP_OPT_DGST_VERIFY, HITLS_APP_OPT_VALUETYPE_IN_FILE, "Public key for signature verification"},
{"signature", HITLS_APP_OPT_DGST_SIGNATURE, HITLS_APP_OPT_VALUETYPE_IN_FILE, "Signature to be verified"},
{"userid", HITLS_APP_OPT_DGST_USERID, HITLS_APP_OPT_VALUETYPE_STRING, "User ID for SM2"},
HITLS_APP_PROV_OPTIONS,
#ifdef HITLS_APP_SM_MODE
HITLS_SM_OPTIONS,
#endif
{"file...", HITLS_APP_OPT_DGST_FILE, HITLS_APP_OPT_VALUETYPE_PARAMTERS, "Files to be digested"},
{NULL, 0, 0, NULL}
};
typedef struct {
char *algName;
int32_t algId;
uint32_t digestSize;
} AlgInfo;
typedef struct {
char *privateKeyFile;
char *publicKeyFile;
char *signatureFile;
char *userid;
AppProvider *provider;
#ifdef HITLS_APP_SM_MODE
HITLS_APP_SM_Param *smParam;
#endif
} SignInfo;
static AlgInfo g_dgstInfo = {"sha256", CRYPT_MD_SHA256, 0};
#ifdef HITLS_APP_SM_MODE
static SignInfo g_signInfo = {NULL, NULL, NULL, "1234567812345678", NULL, NULL};
#else
static SignInfo g_signInfo = {NULL, NULL, NULL, "1234567812345678", NULL};
#endif
static int32_t g_argc = 0;
static char **g_argv;
static CRYPT_EAL_MdCtx *InitAlgDigest(CRYPT_MD_AlgId id)
{
CRYPT_EAL_MdCtx *ctx = CRYPT_EAL_ProviderMdNewCtx(APP_GetCurrent_LibCtx(), id, g_signInfo.provider->providerAttr);
if (ctx == NULL) {
AppPrintError("dgst: Failed to create the algorithm(%s) context\n", g_dgstInfo.algName);
return NULL;
}
int32_t ret = CRYPT_EAL_MdInit(ctx);
if (ret != CRYPT_SUCCESS) {
AppPrintError("dgst: Summary context creation failed\n");
CRYPT_EAL_MdFreeCtx(ctx);
return NULL;
}
return ctx;
}
static int32_t HashValToFinal(
uint8_t *hashBuf, uint32_t hashBufLen, uint8_t **buf, uint32_t *bufLen, const char *filename)
{
int32_t outRet;
uint32_t hexBufLen = hashBufLen * 2;
char *hexBuf = (char *)BSL_SAL_Calloc(hexBufLen + 1, 1);
if (hexBuf == NULL) {
AppPrintError("dgst: Failed to alloc memory.\n");
return HITLS_APP_MEM_ALLOC_FAIL;
}
if (HITLS_APP_BytesToHex(hashBuf, hashBufLen, hexBuf, hexBufLen + 1) != HITLS_APP_SUCCESS) {
BSL_SAL_FREE(hexBuf);
return HITLS_APP_ENCODE_FAIL;
}
uint32_t outBufLen;
if (g_argc == 0) {
outBufLen = strlen("(stdin)= \n") + hexBufLen;
} else {
outBufLen = strlen(g_dgstInfo.algName) + strlen("()= \n") + strlen(filename) + hexBufLen;
}
char *outBuf = (char *)BSL_SAL_Calloc(outBufLen + 1, 1);
if (outBuf == NULL) {
AppPrintError("dgst: Failed to alloc memory.\n");
BSL_SAL_FREE(hexBuf);
return HITLS_APP_MEM_ALLOC_FAIL;
}
if (g_argc == 0) {
outRet = snprintf(outBuf, outBufLen + 1, "(stdin)= %s\n", hexBuf);
} else {
outRet = snprintf(outBuf, outBufLen + 1, "%s(%s)= %s\n", g_dgstInfo.algName, filename, hexBuf);
}
BSL_SAL_FREE(hexBuf);
if (outRet < 0) {
BSL_SAL_FREE(outBuf);
AppPrintError("dgst: Failed to combine the output content\n");
return HITLS_APP_ENCODE_FAIL;
}
*buf = (uint8_t *)outBuf;
*bufLen = outRet;
return HITLS_APP_SUCCESS;
}
static int32_t MdFinalToBuf(CRYPT_EAL_MdCtx *ctx, uint8_t **buf, uint32_t *bufLen, const char *filename)
{
int32_t outRet = HITLS_APP_SUCCESS;
uint8_t *hashBuf = (uint8_t *)BSL_SAL_Calloc(g_dgstInfo.digestSize + 1, 1);
if (hashBuf == NULL) {
AppPrintError("dgst: Failed to alloc memory.\n");
return HITLS_APP_MEM_ALLOC_FAIL;
}
uint32_t hashBufLen = g_dgstInfo.digestSize;
outRet = CRYPT_EAL_MdFinal(ctx, hashBuf, &hashBufLen);
if (outRet != CRYPT_SUCCESS || hashBufLen < g_dgstInfo.digestSize) {
BSL_SAL_FREE(hashBuf);
AppPrintError("dgst: filename: %s Failed to complete the final summary\n", filename);
return HITLS_APP_CRYPTO_FAIL;
}
outRet = HashValToFinal(hashBuf, hashBufLen, buf, bufLen, filename);
BSL_SAL_FREE(hashBuf);
return outRet;
}
static int32_t BufOutToUio(const char *outfile, BSL_UIO *fileWriteUio, uint8_t *outBuf, uint32_t outBufLen)
{
int32_t outRet = HITLS_APP_SUCCESS;
if (outfile == NULL) {
BSL_UIO *stdOutUio = HITLS_APP_UioOpen(NULL, 'w', 0);
if (stdOutUio == NULL) {
AppPrintError("dgst: Failed to open the stdin\n");
return HITLS_APP_UIO_FAIL;
}
outRet = HITLS_APP_OptWriteUio(stdOutUio, outBuf, outBufLen, HITLS_APP_FORMAT_TEXT);
BSL_UIO_Free(stdOutUio);
if (outRet != HITLS_APP_SUCCESS) {
AppPrintError("dgst: Failed to output the content to the screen\n");
return HITLS_APP_UIO_FAIL;
}
} else {
outRet = HITLS_APP_OptWriteUio(fileWriteUio, outBuf, outBufLen, HITLS_APP_FORMAT_TEXT);
if (outRet != HITLS_APP_SUCCESS) {
AppPrintError("dgst: Failed to export data to the file path: <%s>\n", outfile);
return HITLS_APP_UIO_FAIL;
}
}
return HITLS_APP_SUCCESS;
}
static int32_t StdSumAndOut(CRYPT_EAL_MdCtx *ctx, const char *outfile)
{
int32_t stdRet = HITLS_APP_SUCCESS;
uint8_t *outBuf = NULL;
uint32_t outBufLen = 0;
BSL_UIO *readUio = HITLS_APP_UioOpen(NULL, 'r', 0);
if (readUio == NULL) {
AppPrintError("dgst: Failed to open the stdin\n");
return HITLS_APP_UIO_FAIL;
}
uint32_t readLen = MAX_DIGEST_SIZE;
uint8_t *readBuf = (uint8_t *)BSL_SAL_Calloc(MAX_DIGEST_SIZE + 1, 1);
if (readBuf == NULL) {
BSL_UIO_Free(readUio);
AppPrintError("dgst: Failed to alloc memory.\n");
return HITLS_APP_MEM_ALLOC_FAIL;
}
bool isEof = false;
while (BSL_UIO_Ctrl(readUio, BSL_UIO_FILE_GET_EOF, IS_SUPPORT_GET_EOF, &isEof) == BSL_SUCCESS && !isEof) {
if (BSL_UIO_Read(readUio, readBuf, MAX_DIGEST_SIZE, &readLen) != BSL_SUCCESS) {
AppPrintError("dgst: Failed to obtain the content from the STDIN\n");
stdRet = HITLS_APP_STDIN_FAIL;
break;
}
if (readLen == 0) {
break;
}
if (CRYPT_EAL_MdUpdate(ctx, readBuf, readLen) != CRYPT_SUCCESS) {
AppPrintError("dgst: Failed to continuously summarize the STDIN content\n");
stdRet = HITLS_APP_CRYPTO_FAIL;
break;
}
}
BSL_UIO_Free(readUio);
BSL_SAL_FREE(readBuf);
if (stdRet != HITLS_APP_SUCCESS) {
return stdRet;
}
stdRet = MdFinalToBuf(ctx, &outBuf, &outBufLen, "stdin");
if (stdRet != HITLS_APP_SUCCESS) {
BSL_SAL_FREE(outBuf);
return stdRet;
}
BSL_UIO *fileWriteUio = HITLS_APP_UioOpen(outfile, 'w', outfile != NULL ? 1 : 0);
if (fileWriteUio == NULL) {
BSL_SAL_FREE(outBuf);
AppPrintError("dgst: Failed to open the <%s>\n", outfile);
return HITLS_APP_UIO_FAIL;
}
stdRet = BufOutToUio(outfile, fileWriteUio, (uint8_t *)outBuf, outBufLen);
BSL_UIO_Free(fileWriteUio);
BSL_SAL_FREE(outBuf);
return stdRet;
}
static int32_t ReadFileToBuf(CRYPT_EAL_MdCtx *ctx, const char *filename)
{
int32_t readRet = HITLS_APP_SUCCESS;
BSL_UIO *readUio = HITLS_APP_UioOpen(filename, 'r', filename != NULL ? 1 : 0);
if (readUio == NULL) {
AppPrintError("dgst: Failed to open the file <%s>, No such file or directory\n", filename);
return HITLS_APP_UIO_FAIL;
}
uint64_t readFileLen = 0;
readRet = BSL_UIO_Ctrl(readUio, BSL_UIO_PENDING, sizeof(readFileLen), &readFileLen);
if (readRet != BSL_SUCCESS) {
BSL_UIO_Free(readUio);
AppPrintError("dgst: Failed to obtain the content length\n");
return HITLS_APP_UIO_FAIL;
}
uint8_t *readBuf = (uint8_t *)BSL_SAL_Calloc(MAX_DIGEST_SIZE + 1, 1);
if (readBuf == NULL) {
BSL_UIO_Free(readUio);
AppPrintError("dgst: Failed to alloc memory.\n");
return HITLS_APP_MEM_ALLOC_FAIL;
}
while (readFileLen > 0) {
uint32_t bufLen = (readFileLen > MAX_DIGEST_SIZE) ? MAX_DIGEST_SIZE : (uint32_t)readFileLen;
uint32_t readLen = 0;
readRet = BSL_UIO_Read(readUio, readBuf, bufLen, &readLen);
if (readRet != BSL_SUCCESS || bufLen != readLen) {
AppPrintError("dgst: Failed to read the input content\n");
readRet = HITLS_APP_UIO_FAIL;
break;
}
readRet = CRYPT_EAL_MdUpdate(ctx, readBuf, bufLen);
if (readRet != CRYPT_SUCCESS) {
AppPrintError("dgst: Failed to continuously summarize the file content\n");
readRet = HITLS_APP_CRYPTO_FAIL;
break;
}
readFileLen -= bufLen;
}
BSL_UIO_Free(readUio);
BSL_SAL_FREE(readBuf);
return readRet;
}
static int32_t FileSumOutStd(CRYPT_EAL_MdCtx *ctx)
{
int32_t outRet = HITLS_APP_SUCCESS;
for (int i = 0; i < g_argc; ++i) {
outRet = CRYPT_EAL_MdDeinit(ctx);
if (outRet != CRYPT_SUCCESS) {
AppPrintError("dgst: Summary context deinit failed.\n");
return HITLS_APP_CRYPTO_FAIL;
}
outRet = CRYPT_EAL_MdInit(ctx);
if (outRet != CRYPT_SUCCESS) {
AppPrintError("dgst: Summary context creation failed.\n");
return HITLS_APP_CRYPTO_FAIL;
}
outRet = ReadFileToBuf(ctx, g_argv[i]);
if (outRet != HITLS_APP_SUCCESS) {
return HITLS_APP_UIO_FAIL;
}
uint8_t *outBuf = NULL;
uint32_t outBufLen = 0;
outRet = MdFinalToBuf(ctx, &outBuf, &outBufLen, g_argv[i]);
if (outRet != HITLS_APP_SUCCESS) {
BSL_SAL_FREE(outBuf);
AppPrintError("dgst: Failed to output the final summary value\n");
return outRet;
}
BSL_UIO *fileWriteUio = HITLS_APP_UioOpen(NULL, 'w', 0);
if (fileWriteUio == NULL) {
BSL_SAL_FREE(outBuf);
AppPrintError("dgst: Failed to open the stdout\n");
return HITLS_APP_UIO_FAIL;
}
outRet = BufOutToUio(NULL, fileWriteUio, (uint8_t *)outBuf, outBufLen);
BSL_SAL_FREE(outBuf);
BSL_UIO_Free(fileWriteUio);
if (outRet != HITLS_APP_SUCCESS) {
AppPrintError("dgst: Failed to output the hash value\n");
return outRet;
}
}
return HITLS_APP_SUCCESS;
}
static int32_t MultiFileSetCtx(CRYPT_EAL_MdCtx *ctx)
{
int32_t outRet = CRYPT_EAL_MdDeinit(ctx);
if (outRet != CRYPT_SUCCESS) {
AppPrintError("dgst: Summary context deinit failed.\n");
return HITLS_APP_CRYPTO_FAIL;
}
outRet = CRYPT_EAL_MdInit(ctx);
if (outRet != CRYPT_SUCCESS) {
AppPrintError("dgst: Summary context creation failed.\n");
return HITLS_APP_CRYPTO_FAIL;
}
return HITLS_APP_SUCCESS;
}
static int32_t FileSumOutFile(CRYPT_EAL_MdCtx *ctx, const char *outfile)
{
int32_t outRet = HITLS_APP_SUCCESS;
BSL_UIO *fileWriteUio = HITLS_APP_UioOpen(outfile, 'w', outfile != NULL ? 1 : 0);
if (fileWriteUio == NULL) {
AppPrintError("dgst: Failed to open the file path: %s\n", outfile);
return HITLS_APP_UIO_FAIL;
}
BSL_UIO_Free(fileWriteUio);
fileWriteUio = HITLS_APP_UioOpen(outfile, 'a', outfile != NULL ? 1 : 0);
if (fileWriteUio == NULL) {
AppPrintError("dgst: Failed to open the file path: %s\n", outfile);
return HITLS_APP_UIO_FAIL;
}
for (int i = 0; i < g_argc; ++i) {
outRet = MultiFileSetCtx(ctx);
if (outRet != HITLS_APP_SUCCESS) {
BSL_UIO_Free(fileWriteUio);
return outRet;
}
outRet = ReadFileToBuf(ctx, g_argv[i]);
if (outRet != HITLS_APP_SUCCESS) {
BSL_UIO_Free(fileWriteUio);
AppPrintError("dgst: Failed to read the file content by block and calculate the hash value\n");
return HITLS_APP_UIO_FAIL;
}
uint8_t *outBuf = NULL;
uint32_t outBufLen = 0;
outRet = MdFinalToBuf(ctx, &outBuf, &outBufLen, g_argv[i]);
if (outRet != HITLS_APP_SUCCESS) {
BSL_SAL_FREE(outBuf);
BSL_UIO_Free(fileWriteUio);
AppPrintError("dgst: Failed to output the final summary value\n");
return outRet;
}
outRet = BufOutToUio(outfile, fileWriteUio, (uint8_t *)outBuf, outBufLen);
BSL_SAL_FREE(outBuf);
if (outRet != HITLS_APP_SUCCESS) {
BSL_UIO_Free(fileWriteUio);
return outRet;
}
}
BSL_UIO_Free(fileWriteUio);
return HITLS_APP_SUCCESS;
}
static int32_t FileSumAndOut(CRYPT_EAL_MdCtx *ctx, const char *outfile)
{
int32_t outRet = HITLS_APP_SUCCESS;
if (outfile == NULL) {
outRet = FileSumOutStd(ctx);
} else {
outRet = FileSumOutFile(ctx, outfile);
}
return outRet;
}
static int32_t CalculateDgst(char *outfile)
{
int32_t ret = HITLS_APP_SUCCESS;
CRYPT_EAL_MdCtx *ctx = InitAlgDigest(g_dgstInfo.algId);
if (ctx == NULL) {
ret = HITLS_APP_CRYPTO_FAIL;
return ret;
}
#ifdef HITLS_APP_SM_MODE
if (g_signInfo.smParam->smTag == 1) {
g_signInfo.smParam->status = HITLS_APP_SM_STATUS_APPORVED;
}
#endif
if (g_dgstInfo.algId == CRYPT_MD_SHAKE128) {
g_dgstInfo.digestSize = HITLS_APP_SHAKE128_SIZE;
} else if (g_dgstInfo.algId == CRYPT_MD_SHAKE256) {
g_dgstInfo.digestSize = HITLS_APP_SHAKE256_SIZE;
} else {
g_dgstInfo.digestSize = CRYPT_EAL_MdGetDigestSize(g_dgstInfo.algId);
if (g_dgstInfo.digestSize == 0) {
ret = HITLS_APP_CRYPTO_FAIL;
AppPrintError("dgst: Failed to obtain the default length of the algorithm(%s)\n", g_dgstInfo.algName);
CRYPT_EAL_MdFreeCtx(ctx);
return ret;
}
}
ret = (g_argc == 0) ? StdSumAndOut(ctx, outfile) : FileSumAndOut(ctx, outfile);
CRYPT_EAL_MdDeinit(ctx);
CRYPT_EAL_MdFreeCtx(ctx);
return ret;
}
#ifdef HITLS_APP_SM_MODE
static int32_t GetPkeyCtxFromUuid(SignInfo *signInfo, char *uuid, CRYPT_EAL_PkeyCtx **ctx)
{
HITLS_APP_KeyInfo keyInfo = {0};
signInfo->smParam->uuid = uuid;
int32_t ret = HITLS_APP_FindKey(signInfo->provider, signInfo->smParam, CRYPT_PKEY_SM2, &keyInfo);
if (ret != HITLS_APP_SUCCESS) {
AppPrintError("Failed to find key, errCode: 0x%0x.\n", ret);
return ret;
}
*ctx = keyInfo.pkeyCtx;
return HITLS_APP_SUCCESS;
}
#endif
static int32_t CalculateSign(char *outfile, uint8_t *msgBuf, uint32_t msgBufLen)
{
int32_t ret = HITLS_APP_SUCCESS;
uint8_t *prvBuf = NULL;
uint64_t bufLen = 0;
uint8_t *signBuf = NULL;
uint32_t signLen;
BSL_Buffer prv = {0};
CRYPT_EAL_PkeyCtx *ctx = NULL;
do {
#ifdef HITLS_APP_SM_MODE
if (g_signInfo.smParam->smTag == 1) {
ret = GetPkeyCtxFromUuid(&g_signInfo, g_signInfo.privateKeyFile, &ctx);
if (ret != HITLS_APP_SUCCESS) {
break;
}
} else {
#endif
ret = HITLS_APP_ReadFileOrStdin(&prvBuf, &bufLen, g_signInfo.privateKeyFile, MAX_CERT_KEY_SIZE, "dgst");
if (ret != HITLS_APP_SUCCESS) {
break;
}
prv.data = prvBuf;
prv.dataLen = bufLen;
ret = CRYPT_EAL_ProviderDecodeBuffKey(APP_GetCurrent_LibCtx(), g_signInfo.provider->providerAttr,
BSL_CID_UNKNOWN, "PEM", "PRIKEY_PKCS8_UNENCRYPT", &prv, NULL, &ctx);
if (ret != CRYPT_SUCCESS) {
AppPrintError("dgst: Failed to decode the private key, ret=%d\n", ret);
ret = HITLS_APP_CRYPTO_FAIL;
break;
}
#ifdef HITLS_APP_SM_MODE
}
#endif
if (CRYPT_EAL_PkeyGetId(ctx) == CRYPT_PKEY_SM2) {
ret = CRYPT_EAL_PkeyCtrl(ctx, CRYPT_CTRL_SET_SM2_USER_ID, g_signInfo.userid, strlen(g_signInfo.userid));
if (ret != CRYPT_SUCCESS) {
AppPrintError("dgst: Failed to set the SM2 user ID, ret=%d\n", ret);
ret = HITLS_APP_CRYPTO_FAIL;
break;
}
}
#ifdef HITLS_APP_SM_MODE
if (g_signInfo.smParam->smTag == 1) {
g_signInfo.smParam->status = HITLS_APP_SM_STATUS_APPORVED;
}
#endif
signLen = CRYPT_EAL_PkeyGetSignLen(ctx);
if (signLen == 0) {
AppPrintError("dgst: Failed to get the signature length.\n");
ret = HITLS_APP_CRYPTO_FAIL;
break;
}
signBuf = BSL_SAL_Malloc(signLen);
if (signBuf == NULL) {
AppPrintError("dgst: Failed to allocate memory for the signature.\n");
ret = HITLS_APP_MEM_ALLOC_FAIL;
break;
}
ret = CRYPT_EAL_PkeySign(ctx, g_dgstInfo.algId, msgBuf, msgBufLen, signBuf, &signLen);
if (ret != CRYPT_SUCCESS) {
AppPrintError("dgst: Failed to sign the message, ret=%d\n", ret);
ret = HITLS_APP_CRYPTO_FAIL;
break;
}
BSL_UIO *fileWriteUio = HITLS_APP_UioOpen(outfile, 'w', outfile != NULL ? 1 : 0);
if (fileWriteUio == NULL) {
AppPrintError("dgst: Failed to open the outfile\n");
ret = HITLS_APP_UIO_FAIL;
break;
}
ret = HITLS_APP_OptWriteUio(fileWriteUio, signBuf, signLen, HITLS_APP_FORMAT_HEX);
if (ret != HITLS_APP_SUCCESS) {
AppPrintError("dgst:Failed to export data to the outfile path\n");
}
BSL_UIO_Free(fileWriteUio);
} while (0);
CRYPT_EAL_RandDeinitEx(APP_GetCurrent_LibCtx());
BSL_SAL_ClearFree(prvBuf, bufLen);
CRYPT_EAL_PkeyFreeCtx(ctx);
BSL_SAL_FREE(signBuf);
return ret;
}
static int32_t GetPubKeyCtx(CRYPT_EAL_PkeyCtx **ctx)
{
int32_t ret = HITLS_APP_SUCCESS;
uint8_t *pubBuf = NULL;
uint64_t bufLen = 0;
BSL_Buffer pub = {0};
CRYPT_EAL_PkeyCtx *pkeyCtx = NULL;
#ifdef HITLS_APP_SM_MODE
if (g_signInfo.smParam->smTag == 1) {
ret = GetPkeyCtxFromUuid(&g_signInfo, g_signInfo.publicKeyFile, &pkeyCtx);
if (ret == HITLS_APP_SUCCESS) {
*ctx = pkeyCtx;
return HITLS_APP_SUCCESS;
}
}
#endif
ret = HITLS_APP_ReadFileOrStdin(&pubBuf, &bufLen, g_signInfo.publicKeyFile, MAX_CERT_KEY_SIZE, "dgst");
if (ret != HITLS_APP_SUCCESS) {
return ret;
}
pub.data = pubBuf;
pub.dataLen = bufLen;
ret = CRYPT_EAL_ProviderDecodeBuffKey(APP_GetCurrent_LibCtx(), g_signInfo.provider->providerAttr,
BSL_CID_UNKNOWN, "PEM", "PUBKEY_SUBKEY", &pub, NULL, &pkeyCtx);
if (ret != CRYPT_SUCCESS) {
AppPrintError("dgst: Failed to decode the public key, errCode: 0x%0x.\n", ret);
BSL_SAL_ClearFree(pubBuf, bufLen);
return HITLS_APP_CRYPTO_FAIL;
}
BSL_SAL_ClearFree(pubBuf, bufLen);
*ctx = pkeyCtx;
AppPrintInfo("dgst: Get pub key ctx success!\n");
return HITLS_APP_SUCCESS;
}
static int32_t VerifySign(uint8_t *msgBuf, uint32_t msgBufLen)
{
int32_t ret = HITLS_APP_SUCCESS;
uint8_t *signBuf = NULL;
uint64_t signLen = 0;
uint8_t *hexBuf = NULL;
uint32_t hexLen;
CRYPT_EAL_PkeyCtx *ctx = NULL;
do {
ret = GetPubKeyCtx(&ctx);
if (ret != HITLS_APP_SUCCESS) {
break;
}
ret = HITLS_APP_ReadFileOrStdin(&signBuf, &signLen, g_signInfo.signatureFile, UINT32_MAX, "dgst");
if (ret != HITLS_APP_SUCCESS) {
break;
}
hexLen = signLen / APP_HEX_TO_BYTE + 1;
hexBuf = (uint8_t *)BSL_SAL_Malloc(hexLen);
if (hexBuf == NULL) {
AppPrintError("dgst: Failed to alloc memory.\n");
ret = HITLS_APP_MEM_ALLOC_FAIL;
break;
}
ret = HITLS_APP_HexToBytes((const char *)signBuf, hexBuf, &hexLen);
if (ret != HITLS_APP_SUCCESS) {
AppPrintError("dgst: Failed to convert signature to hex, ret=%d\n", ret);
break;
}
if (CRYPT_EAL_PkeyGetId(ctx) == CRYPT_PKEY_SM2) {
ret = CRYPT_EAL_PkeyCtrl(ctx, CRYPT_CTRL_SET_SM2_USER_ID, g_signInfo.userid, strlen(g_signInfo.userid));
if (ret != CRYPT_SUCCESS) {
AppPrintError("dgst: Failed to set the SM2 user ID, ret=%d\n", ret);
ret = HITLS_APP_CRYPTO_FAIL;
break;
}
}
#ifdef HITLS_APP_SM_MODE
if (g_signInfo.smParam->smTag == 1) {
g_signInfo.smParam->status = HITLS_APP_SM_STATUS_APPORVED;
}
#endif
ret = CRYPT_EAL_PkeyVerify(ctx, g_dgstInfo.algId, msgBuf, msgBufLen, hexBuf, hexLen);
if (ret != CRYPT_SUCCESS) {
AppPrintError("dgst: Failed to verify the message, ret=%d\n", ret);
ret = HITLS_APP_CRYPTO_FAIL;
break;
}
AppPrintError("verify success\n");
} while (0);
BSL_SAL_FREE(signBuf);
BSL_SAL_FREE(hexBuf);
CRYPT_EAL_PkeyFreeCtx(ctx);
return ret;
}
static int32_t CheckSmParam(SignInfo *signInfo)
{
#ifdef HITLS_APP_SM_MODE
if (signInfo->smParam->smTag == 1 && signInfo->smParam->workPath == NULL) {
AppPrintError("dgst: The workpath is not specified.\n");
return HITLS_APP_OPT_VALUE_INVALID;
}
#else
(void) signInfo;
#endif
return HITLS_APP_SUCCESS;
}
static int32_t OptParse(char **outfile)
{
HITLSOptType optType;
int ret = HITLS_APP_SUCCESS;
while ((optType = HITLS_APP_OptNext()) != HITLS_APP_OPT_DGST_EOF) {
switch (optType) {
case HITLS_APP_OPT_DGST_EOF:
case HITLS_APP_OPT_DGST_ERR:
ret = HITLS_APP_OPT_UNKOWN;
AppPrintError("dgst: Use -help for summary.\n");
return ret;
case HITLS_APP_OPT_DGST_HELP:
ret = HITLS_APP_HELP;
(void)HITLS_APP_OptHelpPrint(g_dgstOpts);
return ret;
case HITLS_APP_OPT_DGST_OUT:
*outfile = HITLS_APP_OptGetValueStr();
if (*outfile == NULL || strlen(*outfile) >= PATH_MAX) {
AppPrintError("dgst: The length of outfile error, range is (0, 4096).\n");
return HITLS_APP_OPT_VALUE_INVALID;
}
break;
case HITLS_APP_OPT_DGST_ALG:
g_dgstInfo.algName = HITLS_APP_OptGetValueStr();
if (g_dgstInfo.algName == NULL) {
return HITLS_APP_OPT_VALUE_INVALID;
}
g_dgstInfo.algId = HITLS_APP_GetCidByName(g_dgstInfo.algName, HITLS_APP_LIST_OPT_DGST_ALG);
if (g_dgstInfo.algId == BSL_CID_UNKNOWN) {
return HITLS_APP_OPT_VALUE_INVALID;
}
break;
case HITLS_APP_OPT_DGST_SIGN:
g_signInfo.privateKeyFile = HITLS_APP_OptGetValueStr();
if (g_signInfo.privateKeyFile == NULL) {
return HITLS_APP_OPT_VALUE_INVALID;
}
break;
case HITLS_APP_OPT_DGST_VERIFY:
g_signInfo.publicKeyFile = HITLS_APP_OptGetValueStr();
if (g_signInfo.publicKeyFile == NULL) {
return HITLS_APP_OPT_VALUE_INVALID;
}
break;
case HITLS_APP_OPT_DGST_SIGNATURE:
g_signInfo.signatureFile = HITLS_APP_OptGetValueStr();
if (g_signInfo.signatureFile == NULL) {
return HITLS_APP_OPT_VALUE_INVALID;
}
break;
case HITLS_APP_OPT_DGST_USERID:
g_signInfo.userid = HITLS_APP_OptGetValueStr();
if (g_signInfo.userid == NULL) {
return HITLS_APP_OPT_VALUE_INVALID;
}
break;
#ifdef HITLS_APP_SM_MODE
case HITLS_SM_OPT_SM:
case HITLS_SM_OPT_UUID:
case HITLS_SM_OPT_WORKPATH:
#endif
case HITLS_APP_OPT_PROVIDER:
case HITLS_APP_OPT_PROVIDER_PATH:
case HITLS_APP_OPT_PROVIDER_ATTR:
break;
default:
return HITLS_APP_OPT_UNKOWN;
}
HITLS_APP_PROV_CASES(optType, g_signInfo.provider);
#ifdef HITLS_APP_SM_MODE
HITLS_APP_SM_CASES(optType, g_signInfo.smParam);
#endif
}
return HITLS_APP_SUCCESS;
}
int32_t HITLS_DgstMain(int argc, char *argv[])
{
AppProvider appProvider = {NULL, NULL, NULL};
g_signInfo.provider = &appProvider;
#ifdef HITLS_APP_SM_MODE
HITLS_APP_SM_Param smParam = {NULL, 0, NULL, NULL, 0, HITLS_APP_SM_STATUS_OPEN};
AppInitParam initParam = {CRYPT_RAND_SHA256, &appProvider, &smParam};
g_signInfo.smParam = &smParam;
#else
AppInitParam initParam = {CRYPT_RAND_SHA256, &appProvider};
#endif
char *outfile = NULL;
char *msgFile = NULL;
uint8_t *msgBuf = NULL;
uint64_t msgBufLen = 0;
int32_t mainRet = HITLS_APP_SUCCESS;
mainRet = HITLS_APP_OptBegin(argc, argv, g_dgstOpts);
if (mainRet != HITLS_APP_SUCCESS) {
AppPrintError("dgst: error in opt begin.\n");
goto end;
}
mainRet = OptParse(&outfile);
if (mainRet != HITLS_APP_SUCCESS) {
goto end;
}
mainRet = CheckSmParam(&g_signInfo);
if (mainRet != HITLS_APP_SUCCESS) {
goto end;
}
mainRet = HITLS_APP_Init(&initParam);
if (mainRet != HITLS_APP_SUCCESS) {
AppPrintError("dgst: Failed to init the application, errCode: 0x%x.\n", mainRet);
goto end;
}
g_argc = HITLS_APP_GetRestOptNum();
g_argv = HITLS_APP_GetRestOpt();
if (g_argc !=0) {
msgFile = g_argv[0];
}
if (g_signInfo.privateKeyFile == NULL && g_signInfo.publicKeyFile == NULL) {
mainRet = CalculateDgst(outfile);
} else if (g_signInfo.privateKeyFile != NULL && g_signInfo.publicKeyFile == NULL) {
mainRet = HITLS_APP_ReadFileOrStdin(&msgBuf, &msgBufLen, msgFile, UINT32_MAX, "dgst");
if (mainRet != HITLS_APP_SUCCESS) {
goto end;
}
mainRet = CalculateSign(outfile, msgBuf, (uint32_t)msgBufLen);
} else if (g_signInfo.publicKeyFile != NULL && g_signInfo.signatureFile != NULL) {
mainRet = HITLS_APP_ReadFileOrStdin(&msgBuf, &msgBufLen, msgFile, UINT32_MAX, "dgst");
if (mainRet != HITLS_APP_SUCCESS) {
goto end;
}
mainRet = VerifySign(msgBuf, msgBufLen);
} else {
AppPrintError("dgst: Please add the signature file using the [-signature] option.\n");
mainRet = HITLS_APP_INVALID_ARG;
}
end:
BSL_SAL_FREE(msgBuf);
HITLS_APP_Deinit(&initParam, mainRet);
HITLS_APP_OptEnd();
return mainRet;
}