blob: 2ac82506ef733cc079575432bf5fce6ae87b365e [file] [log] [blame]
Gaurav Shah23a2f3a2010-02-26 15:09:43 -08001// 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>
Gaurav Shah3d4cb842010-02-26 15:39:21 -080012#include <stdint.h> // Needed for UINT16_MAX.
Gaurav Shah23a2f3a2010-02-26 15:09:43 -080013#include <stdlib.h>
Gaurav Shah3d4cb842010-02-26 15:39:21 -080014#include <unistd.h>
Gaurav Shah23a2f3a2010-02-26 15:09:43 -080015
16#include <iostream>
17
18extern "C" {
19#include "file_keys.h"
20#include "firmware_image.h"
21#include "padding.h"
22#include "rsa_utility.h"
23#include "sha_utility.h"
24#include "utility.h"
25}
26
27extern int errno;
28using std::cerr;
29
30namespace vboot_reference {
31
32FirmwareUtility::FirmwareUtility():
33 image_(NULL),
34 root_key_pub_(NULL),
35 firmware_version_(-1),
Gaurav Shahf5564fa2010-03-02 15:40:01 -080036 firmware_key_version_(-1),
37 firmware_sign_algorithm_(-1),
Gaurav Shah23a2f3a2010-02-26 15:09:43 -080038 is_generate_(false),
39 is_verify_(false) {
40}
41
42FirmwareUtility::~FirmwareUtility() {
43 RSAPublicKeyFree(root_key_pub_);
44 FirmwareImageFree(image_);
45}
46
47void FirmwareUtility::PrintUsage(void) {
48 cerr <<
49 "Utility to generate/verify a verified boot firmware image\n\n"
50 "Usage: firmware_utility <--generate|--verify> [OPTIONS]\n\n"
51 "For \"--verify\", required OPTIONS are:\n"
52 "--in <infile>\t\t\tVerified boot firmware image to verify.\n"
53 "--root_key_pub <pubkeyfile>\tPre-processed public root key "
54 "to use for verification.\n\n"
55 "For \"--generate\", required OPTIONS are:\n"
56 "--root_key <privkeyfile>\tPrivate root key file\n"
Gaurav Shahf5564fa2010-03-02 15:40:01 -080057 "--firmware_sign_key <privkeyfile>\tPrivate signing key file\n"
58 "--firmware_sign_key_pub <pubkeyfile>\tPre-processed public signing"
Gaurav Shah23a2f3a2010-02-26 15:09:43 -080059 " key\n"
Gaurav Shahf5564fa2010-03-02 15:40:01 -080060 "--firmware_sign_algorithm <algoid>\tSigning algorithm to use\n"
61 "--firmware_key_version <version#>\tSigning Key Version#\n"
Gaurav Shah23a2f3a2010-02-26 15:09:43 -080062 "--firmware_version <version#>\tFirmware Version#\n"
63 "--in <infile>\t\t\tFirmware Image to sign\n"
64 "--out <outfile>\t\t\tOutput file for verified boot firmware image\n\n"
65 "<algoid> (for --sign-algorithm) is one of the following:\n";
66 for (int i = 0; i < kNumAlgorithms; i++) {
67 cerr << i << " for " << algo_strings[i] << "\n";
68 }
69 cerr << "\n\n";
70}
71
72bool FirmwareUtility::ParseCmdLineOptions(int argc, char* argv[]) {
73 int option_index;
74 static struct option long_options[] = {
75 {"root_key", 1, 0, 0},
76 {"root_key_pub", 1, 0, 0},
Gaurav Shahf5564fa2010-03-02 15:40:01 -080077 {"firmware_sign_key", 1, 0, 0},
78 {"firmware_sign_key_pub", 1, 0, 0},
79 {"firmware_sign_algorithm", 1, 0, 0},
80 {"firmware_key_version", 1, 0, 0},
Gaurav Shah23a2f3a2010-02-26 15:09:43 -080081 {"firmware_version", 1, 0, 0},
82 {"in", 1, 0, 0},
83 {"out", 1, 0, 0},
84 {"generate", 0, 0, 0},
85 {"verify", 0, 0, 0},
86 {NULL, 0, 0, 0}
87 };
88 while (1) {
89 int i = getopt_long(argc, argv, "", long_options, &option_index);
90 if (-1 == i) // Done with option processing.
91 break;
92 if ('?' == i) // Invalid option found.
93 return false;
94
95 if (0 == i) {
Gaurav Shah80d129b2010-03-03 17:58:43 -080096 switch (option_index) {
Gaurav Shah23a2f3a2010-02-26 15:09:43 -080097 case 0: // root_key
98 root_key_file_ = optarg;
99 break;
100 case 1: // root_key_pub
101 root_key_pub_file_ = optarg;
102 break;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800103 case 2: // firmware_sign_key
Gaurav Shah80d129b2010-03-03 17:58:43 -0800104 firmware_key_file_ = optarg;
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800105 break;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800106 case 3: // firmware_sign_key_pub
Gaurav Shah80d129b2010-03-03 17:58:43 -0800107 firmware_key_pub_file_ = optarg;
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800108 break;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800109 case 4: // firmware_sign_algorithm
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800110 errno = 0; // strtol() returns an error via errno
Gaurav Shah80d129b2010-03-03 17:58:43 -0800111 firmware_sign_algorithm_ = strtol(optarg,
112 reinterpret_cast<char**>(NULL), 10);
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800113 if (errno)
114 return false;
115 break;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800116 case 5: // firmware_key_version
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800117 errno = 0;
Gaurav Shah80d129b2010-03-03 17:58:43 -0800118 firmware_key_version_ = strtol(optarg,
119 reinterpret_cast<char**>(NULL), 10);
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800120 if (errno)
121 return false;
122 break;
123 case 6: // firmware_version
124 errno = 0;
Gaurav Shah80d129b2010-03-03 17:58:43 -0800125 firmware_version_ = strtol(optarg,
126 reinterpret_cast<char**>(NULL), 10);
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800127 if (errno)
128 return false;
129 break;
130 case 7: // in
131 in_file_ = optarg;
132 break;
133 case 8: // out
134 out_file_ = optarg;
135 break;
136 case 9: // generate
137 is_generate_ = true;
138 break;
139 case 10: // verify
140 is_verify_ = true;
141 break;
142 }
143 }
144 }
145 return CheckOptions();
146}
147
148
149void FirmwareUtility::OutputSignedImage(void) {
150 if (image_) {
151 if (!WriteFirmwareImage(out_file_.c_str(), image_)) {
152 cerr << "Couldn't write verified boot image to file "
153 << out_file_ <<".\n";
154 }
155 }
156}
157
158bool FirmwareUtility::GenerateSignedImage(void) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800159 uint32_t firmware_sign_key_pub_len;
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800160 uint8_t* header_checksum;
161 DigestContext ctx;
162 image_ = FirmwareImageNew();
163
164 Memcpy(image_->magic, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE);
165
166 // Copy pre-processed public signing key.
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800167 image_->firmware_sign_algorithm = (uint16_t) firmware_sign_algorithm_;
168 image_->firmware_sign_key = BufferFromFile(
Gaurav Shah80d129b2010-03-03 17:58:43 -0800169 firmware_key_pub_file_.c_str(),
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800170 &firmware_sign_key_pub_len);
171 if (!image_->firmware_sign_key)
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800172 return false;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800173 image_->firmware_key_version = firmware_key_version_;
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800174
175 // Update header length.
Gaurav Shah80d129b2010-03-03 17:58:43 -0800176 image_->header_len = GetFirmwareHeaderLen(image_);
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800177
178 // Calculate header checksum.
179 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
Gaurav Shah80d129b2010-03-03 17:58:43 -0800180 DigestUpdate(&ctx, reinterpret_cast<uint8_t*>(&image_->header_len),
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800181 sizeof(image_->header_len));
Gaurav Shah80d129b2010-03-03 17:58:43 -0800182 DigestUpdate(&ctx,
183 reinterpret_cast<uint8_t*>(&image_->firmware_sign_algorithm),
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800184 sizeof(image_->firmware_sign_algorithm));
185 DigestUpdate(&ctx, image_->firmware_sign_key,
186 RSAProcessedKeySize(image_->firmware_sign_algorithm));
Gaurav Shah80d129b2010-03-03 17:58:43 -0800187 DigestUpdate(&ctx, reinterpret_cast<uint8_t*>(&image_->firmware_key_version),
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800188 sizeof(image_->firmware_key_version));
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800189 header_checksum = DigestFinal(&ctx);
190 Memcpy(image_->header_checksum, header_checksum, SHA512_DIGEST_SIZE);
191 Free(header_checksum);
192
193 image_->firmware_version = firmware_version_;
194 image_->firmware_len = 0;
195 // TODO(gauravsh): Populate this with the right bytes once we decide
196 // what goes into the preamble.
197 Memset(image_->preamble, 'P', FIRMWARE_PREAMBLE_SIZE);
198 image_->firmware_data = BufferFromFile(in_file_.c_str(),
199 &image_->firmware_len);
200 if (!image_)
201 return false;
202 // Generate and add the signatures.
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800203 if (!AddFirmwareKeySignature(image_, root_key_file_.c_str())) {
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800204 cerr << "Couldn't write key signature to verified boot image.\n";
205 return false;
206 }
207
Gaurav Shah80d129b2010-03-03 17:58:43 -0800208 if (!AddFirmwareSignature(image_, firmware_key_file_.c_str())) {
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800209 cerr << "Couldn't write firmware signature to verified boot image.\n";
210 return false;
211 }
212 return true;
213}
214
215bool FirmwareUtility::VerifySignedImage(void) {
216 int error;
217 root_key_pub_ = RSAPublicKeyFromFile(root_key_pub_file_.c_str());
218 image_ = ReadFirmwareImage(in_file_.c_str());
219
220 if (!root_key_pub_) {
221 cerr << "Couldn't read pre-processed public root key.\n";
222 return false;
223 }
224
225 if (!image_) {
226 cerr << "Couldn't read firmware image or malformed image.\n";
227 return false;
228 }
Gaurav Shah80d129b2010-03-03 17:58:43 -0800229 if (!(error = VerifyFirmwareImage(root_key_pub_, image_,
230 0))) // Trusted Mode.
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800231 return true;
232 cerr << VerifyFirmwareErrorString(error) << "\n";
233 return false;;
234}
235
236bool FirmwareUtility::CheckOptions(void) {
237 if (is_generate_ == is_verify_) {
238 cerr << "One of --generate or --verify must be specified.\n";
239 return false;
240 }
241 // Common required options.
242 if (in_file_.empty()) {
243 cerr << "No input file specified." << "\n";
244 return false;
245 }
246 // Required options for --verify.
247 if (is_verify_ && root_key_pub_file_.empty()) {
248 cerr << "No pre-processed public root key file specified." << "\n";
249 return false;
250 }
251 // Required options for --generate.
252 if (is_generate_) {
253 if (root_key_file_.empty()) {
254 cerr << "No root key file specified." << "\n";
255 return false;
256 }
Gaurav Shah3d4cb842010-02-26 15:39:21 -0800257 if (firmware_version_ <= 0 || firmware_version_ > UINT16_MAX) {
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800258 cerr << "Invalid or no firmware version specified." << "\n";
259 return false;
260 }
Gaurav Shah80d129b2010-03-03 17:58:43 -0800261 if (firmware_key_file_.empty()) {
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800262 cerr << "No signing key file specified." << "\n";
263 return false;
264 }
Gaurav Shah80d129b2010-03-03 17:58:43 -0800265 if (firmware_key_pub_file_.empty()) {
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800266 cerr << "No pre-processed public signing key file specified." << "\n";
267 return false;
268 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800269 if (firmware_key_version_ <= 0 || firmware_key_version_ > UINT16_MAX) {
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800270 cerr << "Invalid or no key version specified." << "\n";
271 return false;
272 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800273 if (firmware_sign_algorithm_ < 0 ||
274 firmware_sign_algorithm_ >= kNumAlgorithms) {
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800275 cerr << "Invalid or no signing key algorithm specified." << "\n";
276 return false;
277 }
278 if (out_file_.empty()) {
279 cerr <<"No output file specified." << "\n";
280 return false;
281 }
282 }
283 return true;
284}
285
286
287} // namespace vboot_reference
288
289int main(int argc, char* argv[]) {
290 vboot_reference::FirmwareUtility fu;
291 if (!fu.ParseCmdLineOptions(argc, argv)) {
292 fu.PrintUsage();
293 return -1;
294 }
295 if (fu.is_generate()) {
296 if (!fu.GenerateSignedImage())
297 return -1;
298 fu.OutputSignedImage();
299 }
300 if (fu.is_verify()) {
301 cerr << "Verification ";
Gaurav Shah80d129b2010-03-03 17:58:43 -0800302 if (fu.VerifySignedImage())
Gaurav Shah23a2f3a2010-02-26 15:09:43 -0800303 cerr << "SUCCESS.\n";
304 else
305 cerr << "FAILURE.\n";
306 }
307 return 0;
308}