1/*
2 * Copyright (c) 2024-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "digest_common.h"
16#include "signature_tools_log.h"
17#include "openssl/err.h"
18
19namespace OHOS {
20namespace SignatureTools {
21const int32_t DigestCommon::OPENSSL_ERR_MESSAGE_MAX_LEN = 1024;
22
23int32_t DigestCommon::GetDigestAlgorithmOutputSizeBytes(int32_t nId)
24{
25    return EVP_MD_size(EVP_get_digestbynid(nId));
26}
27
28bool DigestCommon::CheckDigestParameter(const DigestParameter& digestParameter)
29{
30    if (digestParameter.md == nullptr) {
31        SIGNATURE_TOOLS_LOGE("md is nullptr");
32        return false;
33    }
34    if (digestParameter.ctxPtr == nullptr) {
35        SIGNATURE_TOOLS_LOGE("ctxPtr is nullptr");
36        return false;
37    }
38    return true;
39}
40
41bool DigestCommon::DigestInit(const DigestParameter& digestParameter)
42{
43    if (!CheckDigestParameter(digestParameter)) {
44        return false;
45    }
46    if (EVP_DigestInit(digestParameter.ctxPtr, digestParameter.md) <= 0) {
47        GetOpensslErrorMessage();
48        SIGNATURE_TOOLS_LOGE("EVP_DigestInit failed");
49        return false;
50    }
51    return true;
52}
53
54/* the caller must ensure that EVP_DigestInit was called before calling this function */
55bool DigestCommon::DigestUpdate(const DigestParameter& digestParameter,
56                                         const unsigned char content[], int32_t len)
57{
58    if (content == nullptr) {
59        SIGNATURE_TOOLS_LOGE("content is nullptr");
60        return false;
61    }
62    if (!CheckDigestParameter(digestParameter)) {
63        return false;
64    }
65    if (EVP_DigestUpdate(digestParameter.ctxPtr, content, len) <= 0) {
66        GetOpensslErrorMessage();
67        SIGNATURE_TOOLS_LOGE("EVP_DigestUpdate failed");
68        return false;
69    }
70    return true;
71}
72
73int32_t DigestCommon::GetDigest(const DigestParameter& digestParameter,
74                                         unsigned char(&out)[EVP_MAX_MD_SIZE])
75{
76    uint32_t outLen = 0;
77    if (!CheckDigestParameter(digestParameter)) {
78        return outLen;
79    }
80    if (EVP_DigestFinal(digestParameter.ctxPtr, out, &outLen) <= 0) {
81        GetOpensslErrorMessage();
82        SIGNATURE_TOOLS_LOGE("EVP_DigestFinal failed");
83        outLen = 0;
84    }
85    return outLen;
86}
87
88int32_t DigestCommon::GetDigest(const ByteBuffer& chunk,
89                                         const std::vector<OptionalBlock>& optionalBlocks,
90                                         const DigestParameter& digestParameter,
91                                         unsigned char(&out)[EVP_MAX_MD_SIZE])
92{
93    int32_t chunkLen = chunk.Remaining();
94    uint32_t outLen = 0;
95    if (digestParameter.md == nullptr) {
96        SIGNATURE_TOOLS_LOGE("md is nullprt");
97        return outLen;
98    }
99    if (digestParameter.ctxPtr == nullptr) {
100        SIGNATURE_TOOLS_LOGE("ctxPtr is nullprt");
101        return outLen;
102    }
103    if (EVP_DigestInit(digestParameter.ctxPtr, digestParameter.md) <= 0) {
104        GetOpensslErrorMessage();
105        SIGNATURE_TOOLS_LOGE("EVP_DigestInit failed");
106        return outLen;
107    }
108    if (EVP_DigestUpdate(digestParameter.ctxPtr, chunk.GetBufferPtr(), chunkLen) <= 0) {
109        GetOpensslErrorMessage();
110        SIGNATURE_TOOLS_LOGE("EVP_DigestUpdate chunk failed");
111        return outLen;
112    }
113    for (int32_t i = 0; i < static_cast<int>(optionalBlocks.size()); i++) {
114        chunkLen = optionalBlocks[i].optionalBlockValue.GetCapacity();
115        if (EVP_DigestUpdate(digestParameter.ctxPtr, optionalBlocks[i].optionalBlockValue.GetBufferPtr(),
116            chunkLen) <= 0) {
117            GetOpensslErrorMessage();
118            SIGNATURE_TOOLS_LOGE("EVP_DigestUpdate %dst optional block failed", i);
119            return outLen;
120        }
121    }
122    if (EVP_DigestFinal(digestParameter.ctxPtr, out, &outLen) <= 0) {
123        GetOpensslErrorMessage();
124        SIGNATURE_TOOLS_LOGE("EVP_DigestFinal failed");
125        outLen = 0;
126    }
127    return outLen;
128}
129
130void DigestCommon::GetOpensslErrorMessage()
131{
132    unsigned long retOpenssl;
133    char errOpenssl[OPENSSL_ERR_MESSAGE_MAX_LEN];
134    while ((retOpenssl = ERR_get_error()) != 0) {
135        ERR_error_string(retOpenssl, errOpenssl);
136        SIGNATURE_TOOLS_LOGE("openssl err: %lu, message: %s", retOpenssl, errOpenssl);
137    }
138}
139
140int32_t DigestCommon::GetDigestAlgorithmId(int32_t signAlgorithm)
141{
142    switch (signAlgorithm) {
143        case ALGORITHM_SHA256_WITH_ECDSA:
144        case ALGORITHM_SHA256_WITH_DSA:
145            return NID_sha256;
146        case ALGORITHM_SHA384_WITH_ECDSA:
147        case ALGORITHM_SHA384_WITH_DSA:
148            return NID_sha384;
149        case ALGORITHM_SHA512_WITH_ECDSA:
150        case ALGORITHM_SHA512_WITH_DSA:
151            return NID_sha512;
152        default:
153            SIGNATURE_TOOLS_LOGE("signAlgorithm: %d error", signAlgorithm);
154            return NID_undef;
155    }
156}
157
158std::string DigestCommon::GetDigestAlgorithmString(int32_t signAlgorithm)
159{
160    switch (signAlgorithm) {
161        case ALGORITHM_SHA256_WITH_ECDSA:
162            return "SHA-256";
163        case ALGORITHM_SHA384_WITH_ECDSA:
164            return "SHA-384";
165        case ALGORITHM_SHA512_WITH_ECDSA:
166            return "SHA-512";
167        default:
168            SIGNATURE_TOOLS_LOGE("signAlgorithm: %d error", signAlgorithm);
169            return "";
170    }
171}
172} // namespace SignatureTools
173} // namespace OHOS