1/*
2 * Copyright (c) 2023 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
16#include "signer_info.h"
17
18#include <openssl/asn1.h>
19#include <openssl/pem.h>
20#include <openssl/obj_mac.h>
21#include <openssl/pkcs7.h>
22#include <openssl/x509.h>
23#include <openssl/objects.h>
24#include <securec.h>
25
26#include "errcode.h"
27#include "log.h"
28#include "openssl_utils.h"
29
30namespace OHOS {
31namespace Security {
32namespace CodeSign {
33static constexpr int INVALID_SIGN_ALGORITHM_NID = -1;
34static constexpr int MAX_SIGNATURE_SIZE = 1024; // 1024: max signature length
35
36// OID used for code signing to mark owner ID
37const std::string SignerInfo::OWNERID_OID = "1.3.6.1.4.1.2011.2.376.1.4.1";
38const std::string SignerInfo::OWNERID_OID_SHORT_NAME = "ownerID";
39const std::string SignerInfo::OWNERID_OID_LONG_NAME = "Code Signature Owner ID";
40
41bool SignerInfo::InitSignerInfo(const std::string &ownerID, X509 *cert, const EVP_MD *md,
42    const ByteBuffer &contentData, bool carrySigningTime)
43{
44    if ((cert == nullptr) || (md == nullptr)) {
45        return false;
46    }
47    md_ = md;
48    carrySigningTime_ = carrySigningTime;
49    p7info_ = PKCS7_SIGNER_INFO_new();
50    if (p7info_ == nullptr) {
51        ERR_LOG_WITH_OPEN_SSL_MSG("Create pkcs7 signer info failed");
52        return false;
53    }
54    bool ret = false;
55    do {
56        // set default information, pkcs7 signer info version is 1
57        if (!ASN1_INTEGER_set(p7info_->version, 1)) {
58            break;
59        }
60
61        // add sign cert info
62        if (!X509_NAME_set(&p7info_->issuer_and_serial->issuer,
63            X509_get_issuer_name(cert))) {
64            break;
65        }
66        ASN1_INTEGER_free(p7info_->issuer_and_serial->serial);
67        if (!(p7info_->issuer_and_serial->serial =
68            ASN1_INTEGER_dup(X509_get_serialNumber(cert)))) {
69            break;
70        }
71
72        // add digest and signature algorithm
73        if (!X509_ALGOR_set0(p7info_->digest_alg, OBJ_nid2obj(EVP_MD_type(md)),
74            V_ASN1_NULL, nullptr)) {
75            break;
76        }
77        int signatureNid = GetSignAlgorithmID(cert);
78        if (signatureNid < 0) {
79            break;
80        }
81        if (!X509_ALGOR_set0(p7info_->digest_enc_alg, OBJ_nid2obj(signatureNid),
82            V_ASN1_NULL, nullptr)) {
83            break;
84        }
85
86        if (!AddAttrsToSignerInfo(ownerID, contentData)) {
87            ERR_LOG_WITH_OPEN_SSL_MSG("Add attributes to signer info failed");
88            break;
89        }
90        ret = true;
91    } while (0);
92    if (!ret) {
93        PKCS7_SIGNER_INFO_free(p7info_);
94        ERR_LOG_WITH_OPEN_SSL_MSG("Init pkcs7 signer info failed");
95    }
96    return ret;
97}
98
99bool SignerInfo::AddAttrsToSignerInfo(const std::string &ownerID, const ByteBuffer &contentData)
100{
101    if (!carrySigningTime_ && ownerID.empty()) {
102        unsignedData_ = std::make_unique<ByteBuffer>();
103        if (!unsignedData_->CopyFrom(contentData.GetBuffer(), contentData.GetSize())) {
104            unsignedData_.reset(nullptr);
105            return false;
106        }
107        return true;
108    }
109
110    if (!ownerID.empty()) {
111        AddOwnerID(ownerID);
112    }
113
114    if (!PKCS7_add_attrib_content_type(p7info_, nullptr)) {
115        return false;
116    }
117
118    if (carrySigningTime_) {
119        if (!PKCS7_add0_attrib_signing_time(p7info_, nullptr)) {
120            return false;
121        }
122    }
123
124    ByteBuffer digest;
125    if (!ComputeDigest(contentData, digest)) {
126        return false;
127    }
128    if (!PKCS7_add1_attrib_digest(p7info_, digest.GetBuffer(), digest.GetSize())) {
129        ERR_LOG_WITH_OPEN_SSL_MSG("PKCS7_add1_attrib_digest fail");
130        return false;
131    }
132    return true;
133}
134
135uint8_t *SignerInfo::GetDataToSign(uint32_t &len)
136{
137    if (p7info_ == nullptr) {
138        return nullptr;
139    }
140
141    uint8_t *data = nullptr;
142    if (p7info_->auth_attr != nullptr) {
143        int itemLen = ASN1_item_i2d(reinterpret_cast<ASN1_VALUE *>(p7info_->auth_attr), &data,
144            ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
145        if (itemLen < 0) {
146            return nullptr;
147        }
148        len = static_cast<uint32_t>(itemLen);
149    } else {
150        if (unsignedData_ == nullptr) {
151            return nullptr;
152        }
153        data = unsignedData_->GetBuffer();
154        len = unsignedData_->GetSize();
155    }
156    return data;
157}
158
159bool SignerInfo::AddSignatureInSignerInfo(const ByteBuffer &signature)
160{
161    if (p7info_ == nullptr) {
162        return false;
163    }
164    uint32_t signatureSize = signature.GetSize();
165    // tmp will be free when freeing p7info_
166    if (signatureSize == 0 || signatureSize > MAX_SIGNATURE_SIZE) {
167        return false;
168    }
169    uint8_t *tmp = static_cast<uint8_t *>(malloc(signatureSize));
170    if (tmp == nullptr) {
171        return false;
172    }
173    (void)memcpy_s(tmp, signatureSize, signature.GetBuffer(), signatureSize);
174    ASN1_STRING_set0(p7info_->enc_digest, tmp, signatureSize);
175    return true;
176}
177
178bool SignerInfo::ComputeDigest(const ByteBuffer &data, ByteBuffer &digest)
179{
180    uint8_t mdBuffer[EVP_MAX_MD_SIZE];
181    uint32_t mdLen = 0;
182    EVP_MD_CTX *mCtx = EVP_MD_CTX_new();
183    bool ret = false;
184    do {
185        if (mCtx == nullptr) {
186            break;
187        }
188        if (!EVP_DigestInit_ex(mCtx, md_, nullptr)) {
189            break;
190        }
191        if (!EVP_DigestUpdate(mCtx, data.GetBuffer(), data.GetSize())) {
192            break;
193        }
194        if (!EVP_DigestFinal_ex(mCtx, mdBuffer, &mdLen)) {
195            break;
196        }
197        ret = true;
198    } while (0);
199    if (!ret) {
200        ERR_LOG_WITH_OPEN_SSL_MSG("Compute digest failed.");
201    } else if (!digest.CopyFrom(mdBuffer, mdLen)) {
202        ret = false;
203    }
204    EVP_MD_CTX_free(mCtx);
205    return ret;
206}
207
208int SignerInfo::GetSignAlgorithmID(const X509 *cert)
209{
210    X509_PUBKEY *xpkey = X509_get_X509_PUBKEY(cert);
211    ASN1_OBJECT *koid = nullptr;
212    if (!X509_PUBKEY_get0_param(&koid, nullptr, nullptr, nullptr, xpkey)) {
213        return INVALID_SIGN_ALGORITHM_NID;
214    }
215    int signatureNid = OBJ_obj2nid(koid);
216    if (signatureNid == NID_rsaEncryption) {
217        return signatureNid;
218    }
219    OBJ_find_sigid_by_algs(&signatureNid, EVP_MD_type(md_), signatureNid);
220    return signatureNid;
221}
222
223PKCS7_SIGNER_INFO *SignerInfo::GetSignerInfo()
224{
225    return p7info_;
226}
227
228int SignerInfo::AddOwnerID(const std::string &ownerID)
229{
230    int nid = CreateNIDFromOID(OWNERID_OID, OWNERID_OID_SHORT_NAME, OWNERID_OID_LONG_NAME);
231    ASN1_STRING *ownerIDAsn1 = ASN1_STRING_new();
232    ASN1_STRING_set(ownerIDAsn1, ownerID.c_str(), ownerID.length());
233    int ret = PKCS7_add_signed_attribute(p7info_, nid, V_ASN1_UTF8STRING, ownerIDAsn1);
234    if (ret == 0) {
235        ASN1_STRING_free(ownerIDAsn1);
236        ERR_LOG_WITH_OPEN_SSL_MSG("PKCS7_add_signed_attribute failed");
237        return CS_ERR_OPENSSL_PKCS7;
238    }
239
240    return CS_SUCCESS;
241}
242
243int SignerInfo::ParseOwnerIdFromSignature(const ByteBuffer &sigbuffer, std::string &ownerID)
244{
245    int nid = CreateNIDFromOID(OWNERID_OID, OWNERID_OID_SHORT_NAME, OWNERID_OID_LONG_NAME);
246    BIO *bio = BIO_new_mem_buf(sigbuffer.GetBuffer(), sigbuffer.GetSize());
247    if (bio == nullptr) {
248        ERR_LOG_WITH_OPEN_SSL_MSG("BIO_new_mem_buf failed");
249        return CS_ERR_OPENSSL_BIO;
250    }
251    PKCS7 *p7 = d2i_PKCS7_bio(bio, nullptr);
252    if (p7 == nullptr) {
253        BIO_free(bio);
254        ERR_LOG_WITH_OPEN_SSL_MSG("d2i_PKCS7_bio failed");
255        return CS_ERR_OPENSSL_PKCS7;
256    }
257
258    STACK_OF(PKCS7_SIGNER_INFO) *signerInfosk = PKCS7_get_signer_info(p7);
259    if (signerInfosk == nullptr) {
260        BIO_free(bio);
261        PKCS7_free(p7);
262        ERR_LOG_WITH_OPEN_SSL_MSG("PKCS7_get_signer_info failed");
263        return CS_ERR_OPENSSL_PKCS7;
264    }
265    for (int i = 0; i < sk_PKCS7_SIGNER_INFO_num(signerInfosk); i++) {
266        PKCS7_SIGNER_INFO *signerInfo = sk_PKCS7_SIGNER_INFO_value(signerInfosk, i);
267        ASN1_TYPE *asn1Type = PKCS7_get_signed_attribute(signerInfo, nid);
268        if (asn1Type != nullptr && asn1Type->type == V_ASN1_UTF8STRING) {
269            ASN1_STRING *result = asn1Type->value.asn1_string;
270            ownerID.assign(reinterpret_cast<const char *>(ASN1_STRING_get0_data(result)), ASN1_STRING_length(result));
271            break;
272        }
273    }
274    BIO_free(bio);
275    PKCS7_free(p7);
276    if (ownerID.empty()) {
277        return CS_ERR_NO_OWNER_ID;
278    }
279    return CS_SUCCESS;
280}
281}
282}
283}
284