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 
30 namespace OHOS {
31 namespace Security {
32 namespace CodeSign {
33 static constexpr int INVALID_SIGN_ALGORITHM_NID = -1;
34 static constexpr int MAX_SIGNATURE_SIZE = 1024; // 1024: max signature length
35 
36 // OID used for code signing to mark owner ID
37 const std::string SignerInfo::OWNERID_OID = "1.3.6.1.4.1.2011.2.376.1.4.1";
38 const std::string SignerInfo::OWNERID_OID_SHORT_NAME = "ownerID";
39 const std::string SignerInfo::OWNERID_OID_LONG_NAME = "Code Signature Owner ID";
40 
InitSignerInfo(const std::string & ownerID,X509 * cert,const EVP_MD * md,const ByteBuffer & contentData,bool carrySigningTime)41 bool 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 
AddAttrsToSignerInfo(const std::string & ownerID,const ByteBuffer & contentData)99 bool 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 
GetDataToSign(uint32_t & len)135 uint8_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 
AddSignatureInSignerInfo(const ByteBuffer & signature)159 bool 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 
ComputeDigest(const ByteBuffer & data,ByteBuffer & digest)178 bool 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 
GetSignAlgorithmID(const X509 * cert)208 int 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 
GetSignerInfo()223 PKCS7_SIGNER_INFO *SignerInfo::GetSignerInfo()
224 {
225     return p7info_;
226 }
227 
AddOwnerID(const std::string & ownerID)228 int 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 
ParseOwnerIdFromSignature(const ByteBuffer & sigbuffer,std::string & ownerID)243 int 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