1 /*
2 * Copyright (c) 2025-2025 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 <algorithm>
17
18 #include "fs_verity_descriptor.h"
19 #include "fs_verity_descriptor_with_sign.h"
20 #include "code_signing.h"
21
22 namespace OHOS {
23 namespace SignatureTools {
24
25 const FsVerityHashAlgorithm FS_SHA256(1, "SHA-256", 256 / 8);
26 const FsVerityHashAlgorithm FS_SHA512(2, "SHA-512", 512 / 8);
27 const int8_t LOG_2_OF_FSVERITY_HASH_PAGE_SIZE = 12;
28 const int FLAG_SELF_SIGN = 1 << 4;
29 const uint8_t ELF_CODE_SIGN_VERSION = 0x3;
30
CodeSigning(SignerConfig * signConfig,bool selfSign)31 CodeSigning::CodeSigning(SignerConfig* signConfig, bool selfSign)
32 {
33 m_signConfig = signConfig;
34 m_selfSign = selfSign;
35 }
36
CodeSigning()37 CodeSigning::CodeSigning()
38 {
39 }
40
GetElfCodeSignBlock(const std::string & input,uint64_t & csOffset,std::vector<int8_t> & codesignData)41 bool CodeSigning::GetElfCodeSignBlock(const std::string &input, uint64_t& csOffset, std::vector<int8_t>& codesignData)
42 {
43 SIGNATURE_TOOLS_LOGI("Start to sign elf code.");
44 std::ifstream inputstream(input, std::ios::binary | std::ios::ate);
45 if (!inputstream.is_open()) {
46 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + input + "failed");
47 return false;
48 }
49 int flags = 0;
50 if (m_selfSign) {
51 flags = flags | FLAG_SELF_SIGN;
52 }
53 std::streamsize fileSize = inputstream.tellg();
54 inputstream.seekg(0, std::ios::beg);
55 std::unique_ptr<FsVerityGenerator> fsVerityGenerator = std::make_unique<FsVerityGenerator>();
56 fsVerityGenerator->SetCsOffset(csOffset);
57 fsVerityGenerator->GenerateFsVerityDigest(inputstream, fileSize, flags);
58 std::vector<int8_t> signature;
59
60 if (!m_selfSign) {
61 std::string ownerID;
62 GetOwnerIdFromCert(ownerID);
63 std::vector<int8_t> fsVerityDigest = fsVerityGenerator->GetFsVerityDigest();
64 bool generateSignatureFlag = GenerateSignature(fsVerityDigest, ownerID, signature);
65 if (!generateSignatureFlag) {
66 SIGNATURE_TOOLS_LOGE("[SignElf] generate elf signature failed");
67 return false;
68 }
69 } else {
70 signature = fsVerityGenerator->GetDescriptorDigest();
71 }
72
73 FsVerityDescriptor::Builder fsdbuilder;
74 fsdbuilder.SetFileSize(fileSize)
75 .SetHashAlgorithm(FS_SHA256.GetId())
76 .SetLog2BlockSize(LOG_2_OF_FSVERITY_HASH_PAGE_SIZE)
77 .SetSaltSize(fsVerityGenerator->GetSaltSize())
78 .SetSignSize(signature.size())
79 .SetSalt(fsVerityGenerator->GetSalt())
80 .SetRawRootHash(fsVerityGenerator->GetRootHash())
81 .SetFlags(flags)
82 .SetCsVersion(ELF_CODE_SIGN_VERSION);
83
84 FsVerityDescriptorWithSign fsVerityDescriptorWithSign =
85 FsVerityDescriptorWithSign(FsVerityDescriptor(fsdbuilder), signature);
86 std::vector<int8_t> treeBytes = fsVerityGenerator->GetTreeBytes();
87 fsVerityDescriptorWithSign.ToByteArray(codesignData);
88 return true;
89 }
90
GenerateSignature(const std::vector<int8_t> & signedData,const std::string & ownerID,std::vector<int8_t> & ret)91 bool CodeSigning::GenerateSignature(const std::vector<int8_t>& signedData, const std::string& ownerID,
92 std::vector<int8_t>& ret)
93 {
94 if (m_signConfig->GetSigner() != nullptr) {
95 STACK_OF(X509)* certs = NULL;
96 certs = m_signConfig->GetSigner()->GetCertificates();
97 if (certs == nullptr) {
98 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "No certificates configured for sign.");
99 return false;
100 }
101 sk_X509_pop_free(certs, X509_free);
102 } else {
103 return false;
104 }
105 std::unique_ptr<BCSignedDataGenerator> bcSignedDataGenerator =
106 std::make_unique<BCSignedDataGenerator>();
107 if (!ownerID.empty()) {
108 SIGNATURE_TOOLS_LOGW("generate signature get owner id not null.");
109 bcSignedDataGenerator->SetOwnerId(ownerID);
110 }
111 std::string signed_data(signedData.begin(), signedData.end());
112 std::string ret_str;
113 if (signedData.empty()) {
114 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Generate verity digest is null");
115 return false;
116 }
117 bool generateSignedDataFlag = bcSignedDataGenerator->GenerateSignedData(signed_data, m_signConfig, ret_str);
118 if (generateSignedDataFlag) {
119 SIGNATURE_TOOLS_LOGE("Generate signedData failed");
120 return false;
121 }
122 ret = std::vector<int8_t>(ret_str.begin(), ret_str.end());
123 return true;
124 }
125
GetOwnerIdFromCert(std::string & ownerID)126 bool CodeSigning::GetOwnerIdFromCert(std::string& ownerID)
127 {
128 if (m_signConfig == nullptr) {
129 ownerID = "";
130 return true;
131 }
132 STACK_OF(X509)* certs = m_signConfig->GetSigner()->GetCertificates();
133 if (sk_X509_num(certs) < MIN_CERT_CHAIN_SIZE) {
134 SIGNATURE_TOOLS_LOGE("sign certs not a cert chain");
135 return false;
136 }
137 X509* cert = sk_X509_value(certs, 0);
138 X509_NAME* subject = X509_get_subject_name(cert);
139 VerifyCertOpensslUtils::GetTextFromX509Name(subject, NID_organizationalUnitName, ownerID);
140 SIGNATURE_TOOLS_LOGI("organizationalUnitName = %s.", ownerID.c_str());
141 return true;
142 }
143 } // namespace SignatureTools
144 } // namespace OHOS
145