1 /* Copyright (c) 2011 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 * Verified boot key block utility 6 */ 7 8 #include <getopt.h> 9 #include <stdint.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include "cryptolib.h" 15 #include "futility.h" 16 #include "host_common.h" 17 #include "util_misc.h" 18 #include "vboot_common.h" 19 20 /* Command line options */ 21 enum { 22 OPT_MODE_PACK = 1000, 23 OPT_MODE_UNPACK, 24 OPT_DATAPUBKEY, 25 OPT_SIGNPUBKEY, 26 OPT_SIGNPRIVATE, 27 OPT_SIGNPRIVATE_PEM, 28 OPT_PEM_ALGORITHM, 29 OPT_EXTERNAL_SIGNER, 30 OPT_FLAGS, 31 }; 32 33 static const struct option long_opts[] = { 34 {"pack", 1, 0, OPT_MODE_PACK}, 35 {"unpack", 1, 0, OPT_MODE_UNPACK}, 36 {"datapubkey", 1, 0, OPT_DATAPUBKEY}, 37 {"signpubkey", 1, 0, OPT_SIGNPUBKEY}, 38 {"signprivate", 1, 0, OPT_SIGNPRIVATE}, 39 {"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM}, 40 {"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM}, 41 {"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER}, 42 {"flags", 1, 0, OPT_FLAGS}, 43 {NULL, 0, 0, 0} 44 }; 45 46 static const char usage[] = 47 "\n" 48 "Usage: " MYNAME " %s <--pack|--unpack> <file> [OPTIONS]\n" 49 "\n" 50 "For '--pack <file>', required OPTIONS are:\n" 51 " --datapubkey <file> Data public key in .vbpubk format\n" 52 "\n" 53 "Optional OPTIONS are:\n" 54 " --signprivate <file>" 55 " Signing private key in .vbprivk format.\n" 56 "OR\n" 57 " --signprivate_pem <file>\n" 58 " --pem_algorithm <algo>\n" 59 " Signing private key in .pem format and algorithm id.\n" 60 "(If one of the above arguments is not specified, the keyblock will\n" 61 "not be signed.)\n" 62 "\n" 63 " --flags <number> Specifies allowed use conditions.\n" 64 " --externalsigner \"cmd\"" 65 " Use an external program cmd to calculate the signatures.\n" 66 "\n" 67 "For '--unpack <file>', optional OPTIONS are:\n" 68 " --signpubkey <file>" 69 " Signing public key in .vbpubk format. This is required to\n" 70 " verify a signed keyblock.\n" 71 " --datapubkey <file>" 72 " Write the data public key to this file.\n\n"; 73 74 static void print_help(const char *progname) 75 { 76 printf(usage, progname); 77 } 78 79 /* Pack a .keyblock */ 80 static int Pack(const char *outfile, const char *datapubkey, 81 const char *signprivate, 82 const char *signprivate_pem, uint64_t pem_algorithm, 83 uint64_t flags, const char *external_signer) 84 { 85 VbPublicKey *data_key; 86 VbPrivateKey *signing_key = NULL; 87 VbKeyBlockHeader *block; 88 89 if (!outfile) { 90 fprintf(stderr, 91 "vbutil_keyblock: Must specify output filename.\n"); 92 return 1; 93 } 94 if (!datapubkey) { 95 fprintf(stderr, 96 "vbutil_keyblock: Must specify data public key.\n"); 97 return 1; 98 } 99 100 data_key = PublicKeyRead(datapubkey); 101 if (!data_key) { 102 fprintf(stderr, "vbutil_keyblock: Error reading data key.\n"); 103 return 1; 104 } 105 106 if (signprivate_pem) { 107 if (pem_algorithm >= kNumAlgorithms) { 108 fprintf(stderr, 109 "vbutil_keyblock: Invalid --pem_algorithm %" 110 PRIu64 "\n", pem_algorithm); 111 return 1; 112 } 113 if (external_signer) { 114 /* External signing uses the PEM file directly. */ 115 block = KeyBlockCreate_external(data_key, 116 signprivate_pem, 117 pem_algorithm, flags, 118 external_signer); 119 } else { 120 signing_key = 121 PrivateKeyReadPem(signprivate_pem, pem_algorithm); 122 if (!signing_key) { 123 fprintf(stderr, "vbutil_keyblock:" 124 " Error reading signing key.\n"); 125 return 1; 126 } 127 block = KeyBlockCreate(data_key, signing_key, flags); 128 } 129 } else { 130 if (signprivate) { 131 signing_key = PrivateKeyRead(signprivate); 132 if (!signing_key) { 133 fprintf(stderr, "vbutil_keyblock:" 134 " Error reading signing key.\n"); 135 return 1; 136 } 137 } 138 block = KeyBlockCreate(data_key, signing_key, flags); 139 } 140 141 free(data_key); 142 if (signing_key) 143 free(signing_key); 144 145 if (0 != KeyBlockWrite(outfile, block)) { 146 fprintf(stderr, "vbutil_keyblock: Error writing key block.\n"); 147 return 1; 148 } 149 free(block); 150 return 0; 151 } 152 153 static int Unpack(const char *infile, const char *datapubkey, 154 const char *signpubkey) 155 { 156 VbPublicKey *data_key; 157 VbPublicKey *sign_key = NULL; 158 VbKeyBlockHeader *block; 159 160 if (!infile) { 161 fprintf(stderr, "vbutil_keyblock: Must specify filename\n"); 162 return 1; 163 } 164 165 block = KeyBlockRead(infile); 166 if (!block) { 167 fprintf(stderr, "vbutil_keyblock: Error reading key block.\n"); 168 return 1; 169 } 170 171 /* If the block is signed, then verify it with the signing public key, 172 * since KeyBlockRead() only verified the hash. */ 173 if (block->key_block_signature.sig_size && signpubkey) { 174 sign_key = PublicKeyRead(signpubkey); 175 if (!sign_key) { 176 fprintf(stderr, 177 "vbutil_keyblock: Error reading signpubkey.\n"); 178 return 1; 179 } 180 if (0 != 181 KeyBlockVerify(block, block->key_block_size, sign_key, 0)) { 182 fprintf(stderr, "vbutil_keyblock:" 183 " Error verifying key block.\n"); 184 return 1; 185 } 186 free(sign_key); 187 } 188 189 printf("Key block file: %s\n", infile); 190 printf("Signature %s\n", sign_key ? "valid" : "ignored"); 191 printf("Flags: %" PRIu64 " ", block->key_block_flags); 192 if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) 193 printf(" !DEV"); 194 if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) 195 printf(" DEV"); 196 if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) 197 printf(" !REC"); 198 if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) 199 printf(" REC"); 200 printf("\n"); 201 202 data_key = &block->data_key; 203 printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, 204 (data_key->algorithm < kNumAlgorithms ? 205 algo_strings[data_key->algorithm] : "(invalid)")); 206 printf("Data key version: %" PRIu64 "\n", data_key->key_version); 207 printf("Data key sha1sum: "); 208 PrintPubKeySha1Sum(data_key); 209 printf("\n"); 210 211 if (datapubkey) { 212 if (0 != PublicKeyWrite(datapubkey, data_key)) { 213 fprintf(stderr, "vbutil_keyblock:" 214 " unable to write public key\n"); 215 return 1; 216 } 217 } 218 219 free(block); 220 return 0; 221 } 222 223 static int do_vbutil_keyblock(int argc, char *argv[]) 224 { 225 226 char *filename = NULL; 227 char *datapubkey = NULL; 228 char *signpubkey = NULL; 229 char *signprivate = NULL; 230 char *signprivate_pem = NULL; 231 char *external_signer = NULL; 232 uint64_t flags = 0; 233 uint64_t pem_algorithm = 0; 234 int is_pem_algorithm = 0; 235 int mode = 0; 236 int parse_error = 0; 237 char *e; 238 int i; 239 240 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { 241 switch (i) { 242 case '?': 243 /* Unhandled option */ 244 printf("Unknown option\n"); 245 parse_error = 1; 246 break; 247 248 case OPT_MODE_PACK: 249 case OPT_MODE_UNPACK: 250 mode = i; 251 filename = optarg; 252 break; 253 254 case OPT_DATAPUBKEY: 255 datapubkey = optarg; 256 break; 257 258 case OPT_SIGNPUBKEY: 259 signpubkey = optarg; 260 break; 261 262 case OPT_SIGNPRIVATE: 263 signprivate = optarg; 264 break; 265 266 case OPT_SIGNPRIVATE_PEM: 267 signprivate_pem = optarg; 268 break; 269 270 case OPT_PEM_ALGORITHM: 271 pem_algorithm = strtoul(optarg, &e, 0); 272 if (!*optarg || (e && *e)) { 273 fprintf(stderr, "Invalid --pem_algorithm\n"); 274 parse_error = 1; 275 } else { 276 is_pem_algorithm = 1; 277 } 278 break; 279 280 case OPT_EXTERNAL_SIGNER: 281 external_signer = optarg; 282 break; 283 284 case OPT_FLAGS: 285 flags = strtoul(optarg, &e, 0); 286 if (!*optarg || (e && *e)) { 287 fprintf(stderr, "Invalid --flags\n"); 288 parse_error = 1; 289 } 290 break; 291 } 292 } 293 294 /* Check if the right combination of options was provided. */ 295 if (signprivate && signprivate_pem) { 296 fprintf(stderr, 297 "Only one of --signprivate or --signprivate_pem must" 298 " be specified\n"); 299 parse_error = 1; 300 } 301 302 if (signprivate_pem && !is_pem_algorithm) { 303 fprintf(stderr, "--pem_algorithm must be used with" 304 " --signprivate_pem\n"); 305 parse_error = 1; 306 } 307 308 if (external_signer && !signprivate_pem) { 309 fprintf(stderr, 310 "--externalsigner must be used with --signprivate_pem" 311 "\n"); 312 parse_error = 1; 313 } 314 315 if (parse_error) { 316 print_help(argv[0]); 317 return 1; 318 } 319 320 switch (mode) { 321 case OPT_MODE_PACK: 322 return Pack(filename, datapubkey, signprivate, 323 signprivate_pem, pem_algorithm, 324 flags, external_signer); 325 case OPT_MODE_UNPACK: 326 return Unpack(filename, datapubkey, signpubkey); 327 default: 328 printf("Must specify a mode.\n"); 329 print_help(argv[0]); 330 return 1; 331 } 332 } 333 334 DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock, 335 VBOOT_VERSION_1_0, 336 "Creates, signs, and verifies a keyblock", 337 print_help); 338