• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <brillo/imageloader/manifest.h>
6 
7 #include <memory>
8 #include <utility>
9 
10 #include <base/json/json_string_value_serializer.h>
11 #include <base/strings/string_number_conversions.h>
12 
13 namespace brillo {
14 namespace imageloader {
15 
16 namespace {
17 // The current version of the manifest file.
18 constexpr int kCurrentManifestVersion = 1;
19 // The name of the version field in the manifest.
20 constexpr char kManifestVersionField[] = "manifest-version";
21 // The name of the component version field in the manifest.
22 constexpr char kVersionField[] = "version";
23 // The name of the field containing the image hash.
24 constexpr char kImageHashField[] = "image-sha256-hash";
25 // The name of the bool field indicating whether component is removable.
26 constexpr char kIsRemovableField[] = "is-removable";
27 // The name of the metadata field.
28 constexpr char kMetadataField[] = "metadata";
29 // The name of the field containing the table hash.
30 constexpr char kTableHashField[] = "table-sha256-hash";
31 // The name of the optional field containing the file system type.
32 constexpr char kFSType[] = "fs-type";
33 
GetSHA256FromString(const std::string & hash_str,std::vector<uint8_t> * bytes)34 bool GetSHA256FromString(const std::string& hash_str,
35                          std::vector<uint8_t>* bytes) {
36   if (!base::HexStringToBytes(hash_str, bytes))
37     return false;
38   return bytes->size() == 32;
39 }
40 
41 // Ensure the metadata entry is a dictionary mapping strings to strings and
42 // parse it into |out_metadata| and return true if so.
ParseMetadata(const base::Value * metadata_element,std::map<std::string,std::string> * out_metadata)43 bool ParseMetadata(const base::Value* metadata_element,
44                    std::map<std::string, std::string>* out_metadata) {
45   DCHECK(out_metadata);
46 
47   const base::DictionaryValue* metadata_dict = nullptr;
48   if (!metadata_element->GetAsDictionary(&metadata_dict))
49     return false;
50 
51   base::DictionaryValue::Iterator it(*metadata_dict);
52   for (; !it.IsAtEnd(); it.Advance()) {
53     std::string parsed_value;
54     if (!it.value().GetAsString(&parsed_value)) {
55       LOG(ERROR) << "Key \"" << it.key() << "\" did not map to string value";
56       return false;
57     }
58 
59     (*out_metadata)[it.key()] = std::move(parsed_value);
60   }
61 
62   return true;
63 }
64 
65 }  // namespace
66 
Manifest()67 Manifest::Manifest() {}
68 
ParseManifest(const std::string & manifest_raw)69 bool Manifest::ParseManifest(const std::string& manifest_raw) {
70   // Now deserialize the manifest json and read out the rest of the component.
71   int error_code;
72   std::string error_message;
73   JSONStringValueDeserializer deserializer(manifest_raw);
74   std::unique_ptr<base::Value> value =
75       deserializer.Deserialize(&error_code, &error_message);
76 
77   if (!value) {
78     LOG(ERROR) << "Could not deserialize the manifest file. Error "
79                << error_code << ": " << error_message;
80     return false;
81   }
82 
83   base::DictionaryValue* manifest_dict = nullptr;
84   if (!value->GetAsDictionary(&manifest_dict)) {
85     LOG(ERROR) << "Could not parse manifest file as JSON.";
86     return false;
87   }
88 
89   // This will have to be changed if the manifest version is bumped.
90   int version;
91   if (!manifest_dict->GetInteger(kManifestVersionField, &version)) {
92     LOG(ERROR) << "Could not parse manifest version field from manifest.";
93     return false;
94   }
95   if (version != kCurrentManifestVersion) {
96     LOG(ERROR) << "Unsupported version of the manifest.";
97     return false;
98   }
99   manifest_version_ = version;
100 
101   std::string image_hash_str;
102   if (!manifest_dict->GetString(kImageHashField, &image_hash_str)) {
103     LOG(ERROR) << "Could not parse image hash from manifest.";
104     return false;
105   }
106 
107   if (!GetSHA256FromString(image_hash_str, &(image_sha256_))) {
108     LOG(ERROR) << "Could not convert image hash to bytes.";
109     return false;
110   }
111 
112   std::string table_hash_str;
113   if (!manifest_dict->GetString(kTableHashField, &table_hash_str)) {
114     LOG(ERROR) << "Could not parse table hash from manifest.";
115     return false;
116   }
117 
118   if (!GetSHA256FromString(table_hash_str, &(table_sha256_))) {
119     LOG(ERROR) << "Could not convert table hash to bytes.";
120     return false;
121   }
122 
123   if (!manifest_dict->GetString(kVersionField, &(version_))) {
124     LOG(ERROR) << "Could not parse component version from manifest.";
125     return false;
126   }
127 
128   // The fs_type field is optional, and squashfs by default.
129   fs_type_ = FileSystem::kSquashFS;
130   std::string fs_type;
131   if (manifest_dict->GetString(kFSType, &fs_type)) {
132     if (fs_type == "ext4") {
133       fs_type_ = FileSystem::kExt4;
134     } else if (fs_type == "squashfs") {
135       fs_type_ = FileSystem::kSquashFS;
136     } else {
137       LOG(ERROR) << "Unsupported file system type: " << fs_type;
138       return false;
139     }
140   }
141 
142   if (!manifest_dict->GetBoolean(kIsRemovableField, &(is_removable_))) {
143     // If is_removable field does not exist, by default it is false.
144     is_removable_ = false;
145   }
146 
147   // Copy out the metadata, if it's there.
148   const base::Value* metadata = nullptr;
149   if (manifest_dict->Get(kMetadataField, &metadata)) {
150     if (!ParseMetadata(metadata, &(metadata_))) {
151       LOG(ERROR) << "Manifest metadata was malformed";
152       return false;
153     }
154   }
155 
156   return true;
157 }
158 
manifest_version() const159 int Manifest::manifest_version() const {
160   return manifest_version_;
161 }
162 
image_sha256() const163 const std::vector<uint8_t>& Manifest::image_sha256() const {
164   return image_sha256_;
165 }
166 
table_sha256() const167 const std::vector<uint8_t>& Manifest::table_sha256() const {
168   return table_sha256_;
169 }
170 
version() const171 const std::string& Manifest::version() const {
172   return version_;
173 }
174 
fs_type() const175 FileSystem Manifest::fs_type() const {
176   return fs_type_;
177 }
178 
is_removable() const179 bool Manifest::is_removable() const {
180   return is_removable_;
181 }
182 
metadata() const183 const std::map<std::string, std::string> Manifest::metadata() const {
184   return metadata_;
185 }
186 
187 }  // namespace imageloader
188 }  // namespace brillo
189