xref: /aosp_15_r20/system/update_engine/payload_consumer/payload_metadata.cc (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
1*5a923131SAndroid Build Coastguard Worker //
2*5a923131SAndroid Build Coastguard Worker // Copyright (C) 2018 The Android Open Source Project
3*5a923131SAndroid Build Coastguard Worker //
4*5a923131SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*5a923131SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*5a923131SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*5a923131SAndroid Build Coastguard Worker //
8*5a923131SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
9*5a923131SAndroid Build Coastguard Worker //
10*5a923131SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*5a923131SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*5a923131SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5a923131SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*5a923131SAndroid Build Coastguard Worker // limitations under the License.
15*5a923131SAndroid Build Coastguard Worker //
16*5a923131SAndroid Build Coastguard Worker 
17*5a923131SAndroid Build Coastguard Worker #include "update_engine/payload_consumer/payload_metadata.h"
18*5a923131SAndroid Build Coastguard Worker 
19*5a923131SAndroid Build Coastguard Worker #include <endian.h>
20*5a923131SAndroid Build Coastguard Worker 
21*5a923131SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
22*5a923131SAndroid Build Coastguard Worker #include <brillo/data_encoding.h>
23*5a923131SAndroid Build Coastguard Worker 
24*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/constants.h"
25*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/hash_calculator.h"
26*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/utils.h"
27*5a923131SAndroid Build Coastguard Worker #include "update_engine/payload_consumer/payload_constants.h"
28*5a923131SAndroid Build Coastguard Worker #include "update_engine/payload_consumer/payload_verifier.h"
29*5a923131SAndroid Build Coastguard Worker 
30*5a923131SAndroid Build Coastguard Worker using std::string;
31*5a923131SAndroid Build Coastguard Worker 
32*5a923131SAndroid Build Coastguard Worker namespace chromeos_update_engine {
33*5a923131SAndroid Build Coastguard Worker 
34*5a923131SAndroid Build Coastguard Worker const uint64_t PayloadMetadata::kDeltaVersionOffset = sizeof(kDeltaMagic);
35*5a923131SAndroid Build Coastguard Worker const uint64_t PayloadMetadata::kDeltaVersionSize = 8;
36*5a923131SAndroid Build Coastguard Worker const uint64_t PayloadMetadata::kDeltaManifestSizeOffset =
37*5a923131SAndroid Build Coastguard Worker     kDeltaVersionOffset + kDeltaVersionSize;
38*5a923131SAndroid Build Coastguard Worker const uint64_t PayloadMetadata::kDeltaManifestSizeSize = 8;
39*5a923131SAndroid Build Coastguard Worker const uint64_t PayloadMetadata::kDeltaMetadataSignatureSizeSize = 4;
40*5a923131SAndroid Build Coastguard Worker 
GetMetadataSignatureSizeOffset() const41*5a923131SAndroid Build Coastguard Worker uint64_t PayloadMetadata::GetMetadataSignatureSizeOffset() const {
42*5a923131SAndroid Build Coastguard Worker   return kDeltaManifestSizeOffset + kDeltaManifestSizeSize;
43*5a923131SAndroid Build Coastguard Worker }
44*5a923131SAndroid Build Coastguard Worker 
GetManifestOffset() const45*5a923131SAndroid Build Coastguard Worker uint64_t PayloadMetadata::GetManifestOffset() const {
46*5a923131SAndroid Build Coastguard Worker   // Actual manifest begins right after the metadata signature size field.
47*5a923131SAndroid Build Coastguard Worker   return kDeltaManifestSizeOffset + kDeltaManifestSizeSize +
48*5a923131SAndroid Build Coastguard Worker          kDeltaMetadataSignatureSizeSize;
49*5a923131SAndroid Build Coastguard Worker }
50*5a923131SAndroid Build Coastguard Worker 
ParsePayloadHeader(const brillo::Blob & payload,ErrorCode * error)51*5a923131SAndroid Build Coastguard Worker MetadataParseResult PayloadMetadata::ParsePayloadHeader(
52*5a923131SAndroid Build Coastguard Worker     const brillo::Blob& payload, ErrorCode* error) {
53*5a923131SAndroid Build Coastguard Worker   return ParsePayloadHeader(payload.data(), payload.size(), error);
54*5a923131SAndroid Build Coastguard Worker }
55*5a923131SAndroid Build Coastguard Worker 
ParsePayloadHeader(const unsigned char * payload,size_t size,ErrorCode * error)56*5a923131SAndroid Build Coastguard Worker MetadataParseResult PayloadMetadata::ParsePayloadHeader(
57*5a923131SAndroid Build Coastguard Worker     const unsigned char* payload, size_t size, ErrorCode* error) {
58*5a923131SAndroid Build Coastguard Worker   // Ensure we have data to cover the major payload version.
59*5a923131SAndroid Build Coastguard Worker   if (size < kDeltaManifestSizeOffset)
60*5a923131SAndroid Build Coastguard Worker     return MetadataParseResult::kInsufficientData;
61*5a923131SAndroid Build Coastguard Worker 
62*5a923131SAndroid Build Coastguard Worker   // Validate the magic string.
63*5a923131SAndroid Build Coastguard Worker   if (memcmp(payload, kDeltaMagic, sizeof(kDeltaMagic)) != 0) {
64*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Bad payload format -- invalid delta magic: "
65*5a923131SAndroid Build Coastguard Worker                << android::base::StringPrintf("%02x%02x%02x%02x",
66*5a923131SAndroid Build Coastguard Worker                                               payload[0],
67*5a923131SAndroid Build Coastguard Worker                                               payload[1],
68*5a923131SAndroid Build Coastguard Worker                                               payload[2],
69*5a923131SAndroid Build Coastguard Worker                                               payload[3])
70*5a923131SAndroid Build Coastguard Worker                << " Expected: "
71*5a923131SAndroid Build Coastguard Worker                << android::base::StringPrintf("%02x%02x%02x%02x",
72*5a923131SAndroid Build Coastguard Worker                                               kDeltaMagic[0],
73*5a923131SAndroid Build Coastguard Worker                                               kDeltaMagic[1],
74*5a923131SAndroid Build Coastguard Worker                                               kDeltaMagic[2],
75*5a923131SAndroid Build Coastguard Worker                                               kDeltaMagic[3]);
76*5a923131SAndroid Build Coastguard Worker     *error = ErrorCode::kDownloadInvalidMetadataMagicString;
77*5a923131SAndroid Build Coastguard Worker     return MetadataParseResult::kError;
78*5a923131SAndroid Build Coastguard Worker   }
79*5a923131SAndroid Build Coastguard Worker 
80*5a923131SAndroid Build Coastguard Worker   uint64_t manifest_offset = GetManifestOffset();
81*5a923131SAndroid Build Coastguard Worker   // Check again with the manifest offset.
82*5a923131SAndroid Build Coastguard Worker   if (size < manifest_offset)
83*5a923131SAndroid Build Coastguard Worker     return MetadataParseResult::kInsufficientData;
84*5a923131SAndroid Build Coastguard Worker 
85*5a923131SAndroid Build Coastguard Worker   // Extract the payload version from the metadata.
86*5a923131SAndroid Build Coastguard Worker   static_assert(sizeof(major_payload_version_) == kDeltaVersionSize,
87*5a923131SAndroid Build Coastguard Worker                 "Major payload version size mismatch");
88*5a923131SAndroid Build Coastguard Worker   memcpy(&major_payload_version_,
89*5a923131SAndroid Build Coastguard Worker          &payload[kDeltaVersionOffset],
90*5a923131SAndroid Build Coastguard Worker          kDeltaVersionSize);
91*5a923131SAndroid Build Coastguard Worker   // Switch big endian to host.
92*5a923131SAndroid Build Coastguard Worker   major_payload_version_ = be64toh(major_payload_version_);
93*5a923131SAndroid Build Coastguard Worker 
94*5a923131SAndroid Build Coastguard Worker   if (major_payload_version_ < kMinSupportedMajorPayloadVersion ||
95*5a923131SAndroid Build Coastguard Worker       major_payload_version_ > kMaxSupportedMajorPayloadVersion) {
96*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Bad payload format -- unsupported payload version: "
97*5a923131SAndroid Build Coastguard Worker                << major_payload_version_;
98*5a923131SAndroid Build Coastguard Worker     *error = ErrorCode::kUnsupportedMajorPayloadVersion;
99*5a923131SAndroid Build Coastguard Worker     return MetadataParseResult::kError;
100*5a923131SAndroid Build Coastguard Worker   }
101*5a923131SAndroid Build Coastguard Worker 
102*5a923131SAndroid Build Coastguard Worker   // Next, parse the manifest size.
103*5a923131SAndroid Build Coastguard Worker   static_assert(sizeof(manifest_size_) == kDeltaManifestSizeSize,
104*5a923131SAndroid Build Coastguard Worker                 "manifest_size size mismatch");
105*5a923131SAndroid Build Coastguard Worker   memcpy(&manifest_size_,
106*5a923131SAndroid Build Coastguard Worker          &payload[kDeltaManifestSizeOffset],
107*5a923131SAndroid Build Coastguard Worker          kDeltaManifestSizeSize);
108*5a923131SAndroid Build Coastguard Worker   manifest_size_ = be64toh(manifest_size_);  // switch big endian to host
109*5a923131SAndroid Build Coastguard Worker 
110*5a923131SAndroid Build Coastguard Worker   metadata_size_ = manifest_offset + manifest_size_;
111*5a923131SAndroid Build Coastguard Worker   if (metadata_size_ < manifest_size_) {
112*5a923131SAndroid Build Coastguard Worker     // Overflow detected.
113*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Overflow detected on manifest size.";
114*5a923131SAndroid Build Coastguard Worker     *error = ErrorCode::kDownloadInvalidMetadataSize;
115*5a923131SAndroid Build Coastguard Worker     return MetadataParseResult::kError;
116*5a923131SAndroid Build Coastguard Worker   }
117*5a923131SAndroid Build Coastguard Worker 
118*5a923131SAndroid Build Coastguard Worker   // Parse the metadata signature size.
119*5a923131SAndroid Build Coastguard Worker   static_assert(
120*5a923131SAndroid Build Coastguard Worker       sizeof(metadata_signature_size_) == kDeltaMetadataSignatureSizeSize,
121*5a923131SAndroid Build Coastguard Worker       "metadata_signature_size size mismatch");
122*5a923131SAndroid Build Coastguard Worker   uint64_t metadata_signature_size_offset = GetMetadataSignatureSizeOffset();
123*5a923131SAndroid Build Coastguard Worker   memcpy(&metadata_signature_size_,
124*5a923131SAndroid Build Coastguard Worker          &payload[metadata_signature_size_offset],
125*5a923131SAndroid Build Coastguard Worker          kDeltaMetadataSignatureSizeSize);
126*5a923131SAndroid Build Coastguard Worker   metadata_signature_size_ = be32toh(metadata_signature_size_);
127*5a923131SAndroid Build Coastguard Worker 
128*5a923131SAndroid Build Coastguard Worker   if (metadata_size_ + metadata_signature_size_ < metadata_size_) {
129*5a923131SAndroid Build Coastguard Worker     // Overflow detected.
130*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Overflow detected on metadata and signature size.";
131*5a923131SAndroid Build Coastguard Worker     *error = ErrorCode::kDownloadInvalidMetadataSize;
132*5a923131SAndroid Build Coastguard Worker     return MetadataParseResult::kError;
133*5a923131SAndroid Build Coastguard Worker   }
134*5a923131SAndroid Build Coastguard Worker   return MetadataParseResult::kSuccess;
135*5a923131SAndroid Build Coastguard Worker }
136*5a923131SAndroid Build Coastguard Worker 
ParsePayloadHeader(const brillo::Blob & payload)137*5a923131SAndroid Build Coastguard Worker bool PayloadMetadata::ParsePayloadHeader(const brillo::Blob& payload) {
138*5a923131SAndroid Build Coastguard Worker   ErrorCode error;
139*5a923131SAndroid Build Coastguard Worker   return ParsePayloadHeader(payload, &error) == MetadataParseResult::kSuccess;
140*5a923131SAndroid Build Coastguard Worker }
141*5a923131SAndroid Build Coastguard Worker 
GetManifest(const brillo::Blob & payload,DeltaArchiveManifest * out_manifest) const142*5a923131SAndroid Build Coastguard Worker bool PayloadMetadata::GetManifest(const brillo::Blob& payload,
143*5a923131SAndroid Build Coastguard Worker                                   DeltaArchiveManifest* out_manifest) const {
144*5a923131SAndroid Build Coastguard Worker   return GetManifest(payload.data(), payload.size(), out_manifest);
145*5a923131SAndroid Build Coastguard Worker }
146*5a923131SAndroid Build Coastguard Worker 
GetManifest(const unsigned char * payload,size_t size,DeltaArchiveManifest * out_manifest) const147*5a923131SAndroid Build Coastguard Worker bool PayloadMetadata::GetManifest(const unsigned char* payload,
148*5a923131SAndroid Build Coastguard Worker                                   size_t size,
149*5a923131SAndroid Build Coastguard Worker                                   DeltaArchiveManifest* out_manifest) const {
150*5a923131SAndroid Build Coastguard Worker   uint64_t manifest_offset = GetManifestOffset();
151*5a923131SAndroid Build Coastguard Worker   CHECK_GE(size, manifest_offset + manifest_size_);
152*5a923131SAndroid Build Coastguard Worker   return out_manifest->ParseFromArray(&payload[manifest_offset],
153*5a923131SAndroid Build Coastguard Worker                                       manifest_size_);
154*5a923131SAndroid Build Coastguard Worker }
155*5a923131SAndroid Build Coastguard Worker 
ValidateMetadataSignature(const brillo::Blob & payload,const string & metadata_signature,const PayloadVerifier & payload_verifier) const156*5a923131SAndroid Build Coastguard Worker ErrorCode PayloadMetadata::ValidateMetadataSignature(
157*5a923131SAndroid Build Coastguard Worker     const brillo::Blob& payload,
158*5a923131SAndroid Build Coastguard Worker     const string& metadata_signature,
159*5a923131SAndroid Build Coastguard Worker     const PayloadVerifier& payload_verifier) const {
160*5a923131SAndroid Build Coastguard Worker   if (payload.size() < metadata_size_ + metadata_signature_size_)
161*5a923131SAndroid Build Coastguard Worker     return ErrorCode::kDownloadMetadataSignatureError;
162*5a923131SAndroid Build Coastguard Worker 
163*5a923131SAndroid Build Coastguard Worker   // A single signature in raw bytes.
164*5a923131SAndroid Build Coastguard Worker   brillo::Blob metadata_signature_blob;
165*5a923131SAndroid Build Coastguard Worker   // The serialized Signatures protobuf message stored in major version >=2
166*5a923131SAndroid Build Coastguard Worker   // payload, it may contain multiple signatures.
167*5a923131SAndroid Build Coastguard Worker   string metadata_signature_protobuf;
168*5a923131SAndroid Build Coastguard Worker   if (!metadata_signature.empty()) {
169*5a923131SAndroid Build Coastguard Worker     // Convert base64-encoded signature to raw bytes.
170*5a923131SAndroid Build Coastguard Worker     if (!brillo::data_encoding::Base64Decode(metadata_signature,
171*5a923131SAndroid Build Coastguard Worker                                              &metadata_signature_blob)) {
172*5a923131SAndroid Build Coastguard Worker       LOG(ERROR) << "Unable to decode base64 metadata signature: "
173*5a923131SAndroid Build Coastguard Worker                  << metadata_signature;
174*5a923131SAndroid Build Coastguard Worker       return ErrorCode::kDownloadMetadataSignatureError;
175*5a923131SAndroid Build Coastguard Worker     }
176*5a923131SAndroid Build Coastguard Worker   } else {
177*5a923131SAndroid Build Coastguard Worker     metadata_signature_protobuf.assign(
178*5a923131SAndroid Build Coastguard Worker         payload.begin() + metadata_size_,
179*5a923131SAndroid Build Coastguard Worker         payload.begin() + metadata_size_ + metadata_signature_size_);
180*5a923131SAndroid Build Coastguard Worker   }
181*5a923131SAndroid Build Coastguard Worker 
182*5a923131SAndroid Build Coastguard Worker   if (metadata_signature_blob.empty() && metadata_signature_protobuf.empty()) {
183*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Missing mandatory metadata signature in both Omaha "
184*5a923131SAndroid Build Coastguard Worker                << "response and payload.";
185*5a923131SAndroid Build Coastguard Worker     return ErrorCode::kDownloadMetadataSignatureMissingError;
186*5a923131SAndroid Build Coastguard Worker   }
187*5a923131SAndroid Build Coastguard Worker 
188*5a923131SAndroid Build Coastguard Worker   brillo::Blob metadata_hash;
189*5a923131SAndroid Build Coastguard Worker   if (!HashCalculator::RawHashOfBytes(
190*5a923131SAndroid Build Coastguard Worker           payload.data(), metadata_size_, &metadata_hash)) {
191*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to compute actual hash of manifest";
192*5a923131SAndroid Build Coastguard Worker     return ErrorCode::kDownloadMetadataSignatureVerificationError;
193*5a923131SAndroid Build Coastguard Worker   }
194*5a923131SAndroid Build Coastguard Worker 
195*5a923131SAndroid Build Coastguard Worker   if (metadata_hash.size() != kSHA256Size) {
196*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Computed actual hash of metadata has incorrect size: "
197*5a923131SAndroid Build Coastguard Worker                << metadata_hash.size();
198*5a923131SAndroid Build Coastguard Worker     return ErrorCode::kDownloadMetadataSignatureVerificationError;
199*5a923131SAndroid Build Coastguard Worker   }
200*5a923131SAndroid Build Coastguard Worker 
201*5a923131SAndroid Build Coastguard Worker   if (!metadata_signature_blob.empty()) {
202*5a923131SAndroid Build Coastguard Worker     brillo::Blob decrypted_signature;
203*5a923131SAndroid Build Coastguard Worker     if (!payload_verifier.VerifyRawSignature(
204*5a923131SAndroid Build Coastguard Worker             metadata_signature_blob, metadata_hash, &decrypted_signature)) {
205*5a923131SAndroid Build Coastguard Worker       LOG(ERROR) << "Manifest hash verification failed. Decrypted hash = ";
206*5a923131SAndroid Build Coastguard Worker       utils::HexDumpVector(decrypted_signature);
207*5a923131SAndroid Build Coastguard Worker       LOG(ERROR) << "Calculated hash before padding = ";
208*5a923131SAndroid Build Coastguard Worker       utils::HexDumpVector(metadata_hash);
209*5a923131SAndroid Build Coastguard Worker       return ErrorCode::kDownloadMetadataSignatureMismatch;
210*5a923131SAndroid Build Coastguard Worker     }
211*5a923131SAndroid Build Coastguard Worker   } else {
212*5a923131SAndroid Build Coastguard Worker     if (!payload_verifier.VerifySignature(metadata_signature_protobuf,
213*5a923131SAndroid Build Coastguard Worker                                           metadata_hash)) {
214*5a923131SAndroid Build Coastguard Worker       LOG(ERROR) << "Manifest hash verification failed.";
215*5a923131SAndroid Build Coastguard Worker       return ErrorCode::kDownloadMetadataSignatureMismatch;
216*5a923131SAndroid Build Coastguard Worker     }
217*5a923131SAndroid Build Coastguard Worker   }
218*5a923131SAndroid Build Coastguard Worker 
219*5a923131SAndroid Build Coastguard Worker   // The autoupdate_CatchBadSignatures test checks for this string in
220*5a923131SAndroid Build Coastguard Worker   // log-files. Keep in sync.
221*5a923131SAndroid Build Coastguard Worker   LOG(INFO) << "Metadata hash signature matches value in Omaha response.";
222*5a923131SAndroid Build Coastguard Worker   return ErrorCode::kSuccess;
223*5a923131SAndroid Build Coastguard Worker }
224*5a923131SAndroid Build Coastguard Worker 
ParsePayloadFile(const string & payload_path,DeltaArchiveManifest * manifest,Signatures * metadata_signatures)225*5a923131SAndroid Build Coastguard Worker bool PayloadMetadata::ParsePayloadFile(const string& payload_path,
226*5a923131SAndroid Build Coastguard Worker                                        DeltaArchiveManifest* manifest,
227*5a923131SAndroid Build Coastguard Worker                                        Signatures* metadata_signatures) {
228*5a923131SAndroid Build Coastguard Worker   brillo::Blob payload;
229*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(
230*5a923131SAndroid Build Coastguard Worker       utils::ReadFileChunk(payload_path, 0, kMaxPayloadHeaderSize, &payload));
231*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(ParsePayloadHeader(payload));
232*5a923131SAndroid Build Coastguard Worker 
233*5a923131SAndroid Build Coastguard Worker   if (manifest != nullptr) {
234*5a923131SAndroid Build Coastguard Worker     TEST_AND_RETURN_FALSE(
235*5a923131SAndroid Build Coastguard Worker         utils::ReadFileChunk(payload_path,
236*5a923131SAndroid Build Coastguard Worker                              kMaxPayloadHeaderSize,
237*5a923131SAndroid Build Coastguard Worker                              GetMetadataSize() - kMaxPayloadHeaderSize,
238*5a923131SAndroid Build Coastguard Worker                              &payload));
239*5a923131SAndroid Build Coastguard Worker     TEST_AND_RETURN_FALSE(GetManifest(payload, manifest));
240*5a923131SAndroid Build Coastguard Worker   }
241*5a923131SAndroid Build Coastguard Worker 
242*5a923131SAndroid Build Coastguard Worker   if (metadata_signatures != nullptr) {
243*5a923131SAndroid Build Coastguard Worker     payload.clear();
244*5a923131SAndroid Build Coastguard Worker     TEST_AND_RETURN_FALSE(utils::ReadFileChunk(
245*5a923131SAndroid Build Coastguard Worker         payload_path, GetMetadataSize(), GetMetadataSignatureSize(), &payload));
246*5a923131SAndroid Build Coastguard Worker     TEST_AND_RETURN_FALSE(
247*5a923131SAndroid Build Coastguard Worker         metadata_signatures->ParseFromArray(payload.data(), payload.size()));
248*5a923131SAndroid Build Coastguard Worker   }
249*5a923131SAndroid Build Coastguard Worker 
250*5a923131SAndroid Build Coastguard Worker   return true;
251*5a923131SAndroid Build Coastguard Worker }
252*5a923131SAndroid Build Coastguard Worker 
253*5a923131SAndroid Build Coastguard Worker }  // namespace chromeos_update_engine
254