Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(385)

Side by Side Diff: src/platform/vboot_reference/utils/firmware_utility.cc

Issue 652216: Vboot reference: A basic user-land verified boot firmware signing and verification utility. (Closed)
Patch Set: Style fixes. Segfault fix. Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/platform/vboot_reference/utils/firmware_utility.c ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 // Utility for manipulating verified boot firmware images.
6 //
7
8 #include "firmware_utility.h"
9
10 #include <errno.h>
11 #include <getopt.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14
15 #include <iostream>
16
17 extern "C" {
18 #include "file_keys.h"
19 #include "firmware_image.h"
20 #include "padding.h"
21 #include "rsa_utility.h"
22 #include "sha_utility.h"
23 #include "utility.h"
24 }
25
26 extern int errno;
27 using std::cerr;
28
29 namespace vboot_reference {
30
31 FirmwareUtility::FirmwareUtility():
32 image_(NULL),
33 root_key_pub_(NULL),
34 firmware_version_(-1),
35 key_version_(-1),
36 sign_algorithm_(-1),
37 is_generate_(false),
38 is_verify_(false) {
39 }
40
41 FirmwareUtility::~FirmwareUtility() {
42 RSAPublicKeyFree(root_key_pub_);
43 FirmwareImageFree(image_);
44 }
45
46 void FirmwareUtility::PrintUsage(void) {
47 cerr <<
48 "Utility to generate/verify a verified boot firmware image\n\n"
49 "Usage: firmware_utility <--generate|--verify> [OPTIONS]\n\n"
50 "For \"--verify\", required OPTIONS are:\n"
51 "--in <infile>\t\t\tVerified boot firmware image to verify.\n"
52 "--root_key_pub <pubkeyfile>\tPre-processed public root key "
53 "to use for verification.\n\n"
54 "For \"--generate\", required OPTIONS are:\n"
55 "--root_key <privkeyfile>\tPrivate root key file\n"
56 "--sign_key <privkeyfile>\tPrivate signing key file\n"
57 "--sign_key_pub <pubkeyfile>\tPre-processed public signing"
58 " key\n"
59 "--sign_algorithm <algoid>\tSigning algorithm to use\n"
60 "--key_version <version#>\tSigning Key Version#\n"
61 "--firmware_version <version#>\tFirmware Version#\n"
62 "--in <infile>\t\t\tFirmware Image to sign\n"
63 "--out <outfile>\t\t\tOutput file for verified boot firmware image\n\n"
64 "<algoid> (for --sign-algorithm) is one of the following:\n";
65 for (int i = 0; i < kNumAlgorithms; i++) {
66 cerr << i << " for " << algo_strings[i] << "\n";
67 }
68 cerr << "\n\n";
69 }
70
71 bool FirmwareUtility::ParseCmdLineOptions(int argc, char* argv[]) {
72 int option_index;
73 static struct option long_options[] = {
74 {"root_key", 1, 0, 0},
75 {"root_key_pub", 1, 0, 0},
76 {"sign_key", 1, 0, 0},
77 {"sign_key_pub", 1, 0, 0},
78 {"sign_algorithm", 1, 0, 0},
79 {"key_version", 1, 0, 0},
80 {"firmware_version", 1, 0, 0},
81 {"in", 1, 0, 0},
82 {"out", 1, 0, 0},
83 {"generate", 0, 0, 0},
84 {"verify", 0, 0, 0},
85 {NULL, 0, 0, 0}
86 };
87 while (1) {
88 int i = getopt_long(argc, argv, "", long_options, &option_index);
89 if (-1 == i) // Done with option processing.
90 break;
91 if ('?' == i) // Invalid option found.
92 return false;
93
94 if (0 == i) {
95 switch(option_index) {
96 case 0: // root_key
97 root_key_file_ = optarg;
98 break;
99 case 1: // root_key_pub
100 root_key_pub_file_ = optarg;
101 break;
102 case 2: // sign_key
103 sign_key_file_ = optarg;
104 break;
105 case 3: // sign_key_pub
106 sign_key_pub_file_ = optarg;
107 break;
108 case 4: // sign_algorithm
109 errno = 0; // strtol() returns an error via errno
110 sign_algorithm_ = strtol(optarg, (char**) NULL, 10);
111 if (errno)
112 return false;
113 break;
114 case 5: // key_version
115 errno = 0;
116 key_version_ = strtol(optarg, (char**) NULL, 10);
117 if (errno)
118 return false;
119 break;
120 case 6: // firmware_version
121 errno = 0;
122 firmware_version_ = strtol(optarg, (char**) NULL, 10);
123 if (errno)
124 return false;
125 break;
126 case 7: // in
127 in_file_ = optarg;
128 break;
129 case 8: // out
130 out_file_ = optarg;
131 break;
132 case 9: // generate
133 is_generate_ = true;
134 break;
135 case 10: // verify
136 is_verify_ = true;
137 break;
138 }
139 }
140 }
141 return CheckOptions();
142 }
143
144
145 void FirmwareUtility::OutputSignedImage(void) {
146 if (image_) {
147 if (!WriteFirmwareImage(out_file_.c_str(), image_)) {
148 cerr << "Couldn't write verified boot image to file "
149 << out_file_ <<".\n";
150 }
151 }
152 }
153
154 bool FirmwareUtility::GenerateSignedImage(void) {
155 uint32_t sign_key_pub_len;
156 uint8_t* header_checksum;
157 DigestContext ctx;
158 image_ = FirmwareImageNew();
159
160 Memcpy(image_->magic, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE);
161
162 // Copy pre-processed public signing key.
163 image_->sign_algorithm = (uint16_t) sign_algorithm_;
164 image_->sign_key = BufferFromFile(sign_key_pub_file_.c_str(),
165 &sign_key_pub_len);
166 if (!image_->sign_key)
167 return false;
168 image_->key_version = key_version_;
169
170 // Update header length.
171 image_->header_len = (sizeof(image_->header_len) +
172 sizeof(image_->sign_algorithm) +
173 sign_key_pub_len +
174 sizeof(image_->key_version) +
175 sizeof(image_->header_checksum));
176
177 // Calculate header checksum.
178 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
179 DigestUpdate(&ctx, (uint8_t*) &image_->header_len,
180 sizeof(image_->header_len));
181 DigestUpdate(&ctx, (uint8_t*) &image_->sign_algorithm,
182 sizeof(image_->sign_algorithm));
183 DigestUpdate(&ctx, image_->sign_key,
184 RSAProcessedKeySize(image_->sign_algorithm));
185 DigestUpdate(&ctx, (uint8_t*) &image_->key_version,
186 sizeof(image_->key_version));
187 header_checksum = DigestFinal(&ctx);
188 Memcpy(image_->header_checksum, header_checksum, SHA512_DIGEST_SIZE);
189 Free(header_checksum);
190
191 image_->firmware_version = firmware_version_;
192 image_->firmware_len = 0;
193 // TODO(gauravsh): Populate this with the right bytes once we decide
194 // what goes into the preamble.
195 Memset(image_->preamble, 'P', FIRMWARE_PREAMBLE_SIZE);
196 image_->firmware_data = BufferFromFile(in_file_.c_str(),
197 &image_->firmware_len);
198 if (!image_)
199 return false;
200 // Generate and add the signatures.
201 if(!AddFirmwareKeySignature(image_, root_key_file_.c_str())) {
202 cerr << "Couldn't write key signature to verified boot image.\n";
203 return false;
204 }
205
206 if(!AddFirmwareSignature(image_, sign_key_file_.c_str(),
207 image_->sign_algorithm)) {
208 cerr << "Couldn't write firmware signature to verified boot image.\n";
209 return false;
210 }
211 return true;
212 }
213
214 bool FirmwareUtility::VerifySignedImage(void) {
215 int error;
216 root_key_pub_ = RSAPublicKeyFromFile(root_key_pub_file_.c_str());
217 image_ = ReadFirmwareImage(in_file_.c_str());
218
219 if (!root_key_pub_) {
220 cerr << "Couldn't read pre-processed public root key.\n";
221 return false;
222 }
223
224 if (!image_) {
225 cerr << "Couldn't read firmware image or malformed image.\n";
226 return false;
227 }
228 if(!(error = VerifyFirmwareImage(root_key_pub_, image_, 0))) // Trusted Mode.
229 return true;
230 cerr << VerifyFirmwareErrorString(error) << "\n";
231 return false;;
232 }
233
234 bool FirmwareUtility::CheckOptions(void) {
235 if (is_generate_ == is_verify_) {
236 cerr << "One of --generate or --verify must be specified.\n";
237 return false;
238 }
239 // Common required options.
240 if (in_file_.empty()) {
241 cerr << "No input file specified." << "\n";
242 return false;
243 }
244 // Required options for --verify.
245 if (is_verify_ && root_key_pub_file_.empty()) {
246 cerr << "No pre-processed public root key file specified." << "\n";
247 return false;
248 }
249 // Required options for --generate.
250 if (is_generate_) {
251 if (root_key_file_.empty()) {
252 cerr << "No root key file specified." << "\n";
253 return false;
254 }
255 if (firmware_version_ <= 0 || firmware_version_ > 0xFFFF) {
256 cerr << "Invalid or no firmware version specified." << "\n";
257 return false;
258 }
259 if (sign_key_file_.empty()) {
260 cerr << "No signing key file specified." << "\n";
261 return false;
262 }
263 if (sign_key_pub_file_.empty()) {
264 cerr << "No pre-processed public signing key file specified." << "\n";
265 return false;
266 }
267 if (key_version_ <= 0 || key_version_ > 0xFFFF) {
268 cerr << "Invalid or no key version specified." << "\n";
269 return false;
270 }
271 if (sign_algorithm_ < 0 || sign_algorithm_ >= kNumAlgorithms) {
272 cerr << "Invalid or no signing key algorithm specified." << "\n";
273 return false;
274 }
275 if (out_file_.empty()) {
276 cerr <<"No output file specified." << "\n";
277 return false;
278 }
279 }
280 return true;
281 }
282
283
284 } // namespace vboot_reference
285
286 int main(int argc, char* argv[]) {
287 vboot_reference::FirmwareUtility fu;
288 if (!fu.ParseCmdLineOptions(argc, argv)) {
289 fu.PrintUsage();
290 return -1;
291 }
292 if (fu.is_generate()) {
293 if (!fu.GenerateSignedImage())
294 return -1;
295 fu.OutputSignedImage();
296 }
297 if (fu.is_verify()) {
298 cerr << "Verification ";
299 if(fu.VerifySignedImage())
300 cerr << "SUCCESS.\n";
301 else
302 cerr << "FAILURE.\n";
303 }
304 return 0;
305 }
OLDNEW
« no previous file with comments | « src/platform/vboot_reference/utils/firmware_utility.c ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698