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