modules/libmar/tool/mar.c

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:535519daa762
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "mar.h"
11 #include "mar_cmdline.h"
12
13 #ifdef XP_WIN
14 #include <windows.h>
15 #include <direct.h>
16 #define chdir _chdir
17 #else
18 #include <unistd.h>
19 #endif
20
21 #if !defined(NO_SIGN_VERIFY) && (!defined(XP_WIN) || defined(MAR_NSS))
22 int NSSInitCryptoContext(const char *NSSConfigDir);
23 #endif
24
25 int mar_repackage_and_sign(const char *NSSConfigDir,
26 const char * const *certNames,
27 uint32_t certCount,
28 const char *src,
29 const char * dest);
30
31 static void print_version() {
32 printf("Version: %s\n", MOZ_APP_VERSION);
33 printf("Default Channel ID: %s\n", MAR_CHANNEL_ID);
34 }
35
36 static void print_usage() {
37 printf("usage:\n");
38 printf("Create a MAR file:\n");
39 printf(" mar [-H MARChannelID] [-V ProductVersion] [-C workingDir] "
40 "-c archive.mar [files...]\n");
41
42 printf("Extract a MAR file:\n");
43 printf(" mar [-C workingDir] -x archive.mar\n");
44 #ifndef NO_SIGN_VERIFY
45 printf("Sign a MAR file:\n");
46 printf(" mar [-C workingDir] -d NSSConfigDir -n certname -s "
47 "archive.mar out_signed_archive.mar\n");
48
49 printf("Strip a MAR signature:\n");
50 printf(" mar [-C workingDir] -r "
51 "signed_input_archive.mar output_archive.mar\n");
52
53 printf("Extract a MAR signature:\n");
54 printf(" mar [-C workingDir] -n(i) -X "
55 "signed_input_archive.mar base_64_encoded_signature_file\n");
56
57 printf("Import a MAR signature:\n");
58 printf(" mar [-C workingDir] -n(i) -I "
59 "signed_input_archive.mar base_64_encoded_signature_file "
60 "changed_signed_output.mar\n");
61 printf("(i) is the index of the certificate to extract\n");
62 #if defined(XP_MACOSX) || (defined(XP_WIN) && !defined(MAR_NSS))
63 printf("Verify a MAR file:\n");
64 printf(" mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n");
65 printf("At most %d signature certificate DER files are specified by "
66 "-D0 DERFilePath1 -D1 DERFilePath2, ...\n", MAX_SIGNATURES);
67 #else
68 printf("Verify a MAR file:\n");
69 printf(" mar [-C workingDir] -d NSSConfigDir -n certname "
70 "-v signed_archive.mar\n");
71 printf("At most %d signature certificate names are specified by "
72 "-n0 certName -n1 certName2, ...\n", MAX_SIGNATURES);
73 #endif
74 printf("At most %d verification certificate names are specified by "
75 "-n0 certName -n1 certName2, ...\n", MAX_SIGNATURES);
76 #endif
77 printf("Print information on a MAR file:\n");
78 printf(" mar -t archive.mar\n");
79
80 printf("Print detailed information on a MAR file including signatures:\n");
81 printf(" mar -T archive.mar\n");
82
83 printf("Refresh the product information block of a MAR file:\n");
84 printf(" mar [-H MARChannelID] [-V ProductVersion] [-C workingDir] "
85 "-i unsigned_archive_to_refresh.mar\n");
86
87 printf("Print executable version:\n");
88 printf(" mar --version\n");
89 printf("This program does not handle unicode file paths properly\n");
90 }
91
92 static int mar_test_callback(MarFile *mar,
93 const MarItem *item,
94 void *unused) {
95 printf("%u\t0%o\t%s\n", item->length, item->flags, item->name);
96 return 0;
97 }
98
99 static int mar_test(const char *path) {
100 MarFile *mar;
101
102 mar = mar_open(path);
103 if (!mar)
104 return -1;
105
106 printf("SIZE\tMODE\tNAME\n");
107 mar_enum_items(mar, mar_test_callback, NULL);
108
109 mar_close(mar);
110 return 0;
111 }
112
113 int main(int argc, char **argv) {
114 char *NSSConfigDir = NULL;
115 const char *certNames[MAX_SIGNATURES];
116 char *MARChannelID = MAR_CHANNEL_ID;
117 char *productVersion = MOZ_APP_VERSION;
118 uint32_t i, k;
119 int rv = -1;
120 uint32_t certCount = 0;
121 int32_t sigIndex = -1;
122
123 #if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
124 HANDLE certFile;
125 uint8_t *certBuffers[MAX_SIGNATURES];
126 #endif
127 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
128 defined(XP_MACOSX))
129 char* DERFilePaths[MAX_SIGNATURES];
130 uint32_t fileSizes[MAX_SIGNATURES];
131 uint32_t read;
132 #endif
133
134 memset(certNames, 0, sizeof(certNames));
135 #if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
136 memset(certBuffers, 0, sizeof(certBuffers));
137 #endif
138 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
139 defined(XP_MACOSX))
140 memset(DERFilePaths, 0, sizeof(DERFilePaths));
141 memset(fileSizes, 0, sizeof(fileSizes));
142 #endif
143
144 if (argc > 1 && 0 == strcmp(argv[1], "--version")) {
145 print_version();
146 return 0;
147 }
148
149 if (argc < 3) {
150 print_usage();
151 return -1;
152 }
153
154 while (argc > 0) {
155 if (argv[1][0] == '-' && (argv[1][1] == 'c' ||
156 argv[1][1] == 't' || argv[1][1] == 'x' ||
157 argv[1][1] == 'v' || argv[1][1] == 's' ||
158 argv[1][1] == 'i' || argv[1][1] == 'T' ||
159 argv[1][1] == 'r' || argv[1][1] == 'X' ||
160 argv[1][1] == 'I')) {
161 break;
162 /* -C workingdirectory */
163 } else if (argv[1][0] == '-' && argv[1][1] == 'C') {
164 chdir(argv[2]);
165 argv += 2;
166 argc -= 2;
167 }
168 #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
169 defined(XP_MACOSX))
170 /* -D DERFilePath, also matches -D[index] DERFilePath
171 We allow an index for verifying to be symmetric
172 with the import and export command line arguments. */
173 else if (argv[1][0] == '-' &&
174 argv[1][1] == 'D' &&
175 (argv[1][2] == (char)('0' + certCount) || argv[1][2] == '\0')) {
176 if (certCount >= MAX_SIGNATURES) {
177 print_usage();
178 return -1;
179 }
180 DERFilePaths[certCount++] = argv[2];
181 argv += 2;
182 argc -= 2;
183 }
184 #endif
185 /* -d NSSConfigdir */
186 else if (argv[1][0] == '-' && argv[1][1] == 'd') {
187 NSSConfigDir = argv[2];
188 argv += 2;
189 argc -= 2;
190 /* -n certName, also matches -n[index] certName
191 We allow an index for verifying to be symmetric
192 with the import and export command line arguments. */
193 } else if (argv[1][0] == '-' &&
194 argv[1][1] == 'n' &&
195 (argv[1][2] == (char)('0' + certCount) ||
196 argv[1][2] == '\0' ||
197 !strcmp(argv[2], "-X") ||
198 !strcmp(argv[2], "-I"))) {
199 if (certCount >= MAX_SIGNATURES) {
200 print_usage();
201 return -1;
202 }
203 certNames[certCount++] = argv[2];
204 if (strlen(argv[1]) > 2 &&
205 (!strcmp(argv[2], "-X") || !strcmp(argv[2], "-I")) &&
206 argv[1][2] >= '0' && argv[1][2] <= '9') {
207 sigIndex = argv[1][2] - '0';
208 argv++;
209 argc--;
210 } else {
211 argv += 2;
212 argc -= 2;
213 }
214 /* MAR channel ID */
215 } else if (argv[1][0] == '-' && argv[1][1] == 'H') {
216 MARChannelID = argv[2];
217 argv += 2;
218 argc -= 2;
219 /* Product Version */
220 } else if (argv[1][0] == '-' && argv[1][1] == 'V') {
221 productVersion = argv[2];
222 argv += 2;
223 argc -= 2;
224 }
225 else {
226 print_usage();
227 return -1;
228 }
229 }
230
231 if (argv[1][0] != '-') {
232 print_usage();
233 return -1;
234 }
235
236 switch (argv[1][1]) {
237 case 'c': {
238 struct ProductInformationBlock infoBlock;
239 infoBlock.MARChannelID = MARChannelID;
240 infoBlock.productVersion = productVersion;
241 return mar_create(argv[2], argc - 3, argv + 3, &infoBlock);
242 }
243 case 'i': {
244 struct ProductInformationBlock infoBlock;
245 infoBlock.MARChannelID = MARChannelID;
246 infoBlock.productVersion = productVersion;
247 return refresh_product_info_block(argv[2], &infoBlock);
248 }
249 case 'T': {
250 struct ProductInformationBlock infoBlock;
251 uint32_t numSignatures, numAdditionalBlocks;
252 int hasSignatureBlock, hasAdditionalBlock;
253 if (!get_mar_file_info(argv[2],
254 &hasSignatureBlock,
255 &numSignatures,
256 &hasAdditionalBlock,
257 NULL, &numAdditionalBlocks)) {
258 if (hasSignatureBlock) {
259 printf("Signature block found with %d signature%s\n",
260 numSignatures,
261 numSignatures != 1 ? "s" : "");
262 }
263 if (hasAdditionalBlock) {
264 printf("%d additional block%s found:\n",
265 numAdditionalBlocks,
266 numAdditionalBlocks != 1 ? "s" : "");
267 }
268
269 rv = read_product_info_block(argv[2], &infoBlock);
270 if (!rv) {
271 printf(" - Product Information Block:\n");
272 printf(" - MAR channel name: %s\n"
273 " - Product version: %s\n",
274 infoBlock.MARChannelID,
275 infoBlock.productVersion);
276 free((void *)infoBlock.MARChannelID);
277 free((void *)infoBlock.productVersion);
278 }
279 }
280 printf("\n");
281 /* The fall through from 'T' to 't' is intentional */
282 }
283 case 't':
284 return mar_test(argv[2]);
285
286 /* Extract a MAR file */
287 case 'x':
288 return mar_extract(argv[2]);
289
290 #ifndef NO_SIGN_VERIFY
291 /* Extract a MAR signature */
292 case 'X':
293 if (sigIndex == -1) {
294 fprintf(stderr, "ERROR: Signature index was not passed.\n");
295 return -1;
296 }
297 if (sigIndex >= MAX_SIGNATURES || sigIndex < -1) {
298 fprintf(stderr, "ERROR: Signature index is out of range: %d.\n",
299 sigIndex);
300 return -1;
301 }
302 return extract_signature(argv[2], sigIndex, argv[3]);
303
304 /* Import a MAR signature */
305 case 'I':
306 if (sigIndex == -1) {
307 fprintf(stderr, "ERROR: signature index was not passed.\n");
308 return -1;
309 }
310 if (sigIndex >= MAX_SIGNATURES || sigIndex < -1) {
311 fprintf(stderr, "ERROR: Signature index is out of range: %d.\n",
312 sigIndex);
313 return -1;
314 }
315 if (argc < 5) {
316 print_usage();
317 return -1;
318 }
319 return import_signature(argv[2], sigIndex, argv[3], argv[4]);
320
321 case 'v':
322
323 #if defined(XP_WIN) && !defined(MAR_NSS)
324 if (certCount == 0) {
325 print_usage();
326 return -1;
327 }
328
329 for (k = 0; k < certCount; ++k) {
330 /* If the mar program was built using CryptoAPI, then read in the buffer
331 containing the cert from disk. */
332 certFile = CreateFileA(DERFilePaths[k], GENERIC_READ,
333 FILE_SHARE_READ |
334 FILE_SHARE_WRITE |
335 FILE_SHARE_DELETE,
336 NULL,
337 OPEN_EXISTING,
338 0, NULL);
339 if (INVALID_HANDLE_VALUE == certFile) {
340 return -1;
341 }
342 fileSizes[k] = GetFileSize(certFile, NULL);
343 certBuffers[k] = malloc(fileSizes[k]);
344 if (!ReadFile(certFile, certBuffers[k], fileSizes[k], &read, NULL) ||
345 fileSizes[k] != read) {
346 CloseHandle(certFile);
347 for (i = 0; i <= k; i++) {
348 free(certBuffers[i]);
349 }
350 return -1;
351 }
352 CloseHandle(certFile);
353 }
354
355 rv = mar_verify_signatures(argv[2], certBuffers, fileSizes,
356 NULL, certCount);
357 for (k = 0; k < certCount; ++k) {
358 free(certBuffers[k]);
359 }
360 if (rv) {
361 /* Determine if the source MAR file has the new fields for signing */
362 int hasSignatureBlock;
363 if (get_mar_file_info(argv[2], &hasSignatureBlock,
364 NULL, NULL, NULL, NULL)) {
365 fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
366 } else if (!hasSignatureBlock) {
367 fprintf(stderr, "ERROR: The MAR file is in the old format so has"
368 " no signature to verify.\n");
369 }
370 return -1;
371 }
372
373 return 0;
374
375 #elif defined(XP_MACOSX)
376 return mar_verify_signatures(argv[2], (const uint8_t* const*)DERFilePaths,
377 0, NULL, certCount);
378 #else
379 if (!NSSConfigDir || certCount == 0) {
380 print_usage();
381 return -1;
382 }
383
384 if (NSSInitCryptoContext(NSSConfigDir)) {
385 fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
386 return -1;
387 }
388
389 return mar_verify_signatures(argv[2], NULL, 0, certNames, certCount);
390
391 #endif /* defined(XP_WIN) && !defined(MAR_NSS) */
392 case 's':
393 if (!NSSConfigDir || certCount == 0 || argc < 4) {
394 print_usage();
395 return -1;
396 }
397 return mar_repackage_and_sign(NSSConfigDir, certNames, certCount,
398 argv[2], argv[3]);
399
400 case 'r':
401 return strip_signature_block(argv[2], argv[3]);
402 #endif /* endif NO_SIGN_VERIFY disabled */
403
404 default:
405 print_usage();
406 return -1;
407 }
408
409 return 0;
410 }

mercurial