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