static int do_create(int argc, char *argv[]) { int errorcnt = 0; char *e, *s; int i, r, len, remove_ext = 0; const struct vb2_text_vs_enum *entry; while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { switch (i) { case OPT_VERSION: opt_version = strtoul(optarg, &e, 0); if (!*optarg || (e && *e)) { fprintf(stderr, "invalid version \"%s\"\n", optarg); errorcnt = 1; } break; case OPT_DESC: opt_desc = optarg; break; case OPT_GUID: if (VB2_SUCCESS != vb2_str_to_guid(optarg, &opt_guid)) { fprintf(stderr, "invalid guid \"%s\"\n", optarg); errorcnt = 1; } break; case OPT_HASH_ALG: /* try string first */ entry = vb2_lookup_by_name(vb2_text_vs_hash, optarg); if (entry) { opt_hash_alg = entry->num; break; } /* fine, try number */ opt_hash_alg = strtoul(optarg, &e, 0); if (!*optarg || (e && *e)) { fprintf(stderr, "invalid hash_alg \"%s\"\n", optarg); errorcnt++; break; } if (!vb2_lookup_by_num(vb2_text_vs_hash, opt_hash_alg)) { fprintf(stderr, "Hash algorithm %d is unsupported\n", opt_hash_alg); errorcnt++; } break; case '?': if (optopt) fprintf(stderr, "Unrecognized option: -%c\n", optopt); else fprintf(stderr, "Unrecognized option\n"); errorcnt++; break; case ':': fprintf(stderr, "Missing argument to -%c\n", optopt); errorcnt++; break; case 0: /* handled option */ break; default: DIE; } } /* If we don't have an input file already, we need one */ if (!infile) { if (argc - optind <= 0) { fprintf(stderr, "ERROR: missing input filename\n"); errorcnt++; } else { infile = argv[optind++]; } } if (errorcnt) { print_help(argv[0]); return 1; } /* Decide how to determine the output filenames. */ if (argc > optind) { s = argv[optind++]; /* just use this */ } else { s = infile; /* based on pem file name */ remove_ext = 1; } /* Make an extra-large copy to leave room for filename extensions */ len = strlen(s) + 20; outfile = (char *)malloc(len); if (!outfile) { fprintf(stderr, "ERROR: malloc() failed\n"); return 1; } strcpy(outfile, s); if (remove_ext) { /* Find the last '/' if any, then the last '.' before that. */ s = strrchr(outfile, '/'); if (!s) s = outfile; s = strrchr(s, '.'); /* Cut off the extension */ if (s) *s = '\0'; } /* Remember that spot for later */ outext = outfile + strlen(outfile); /* Okay, do it */ if (vboot_version == VBOOT_VERSION_1_0) r = vb1_make_keypair(); else r = vb2_make_keypair(); free(outfile); return r; }
static int vb2_sig_from_usbpd1(struct vb2_signature **sig, enum vb2_signature_algorithm sig_alg, enum vb2_hash_algorithm hash_alg, const uint8_t *o_sig, uint32_t o_sig_size, uint32_t data_size) { struct vb2_signature s = { .c.magic = VB2_MAGIC_SIGNATURE, .c.struct_version_major = VB2_SIGNATURE_VERSION_MAJOR, .c.struct_version_minor = VB2_SIGNATURE_VERSION_MINOR, .c.fixed_size = sizeof(s), .sig_alg = sig_alg, .hash_alg = hash_alg, .data_size = data_size, .sig_size = vb2_rsa_sig_size(sig_alg), .sig_offset = sizeof(s), }; uint32_t total_size = sizeof(s) + o_sig_size; uint8_t *buf = calloc(1, total_size); if (!buf) return VB2_ERROR_UNKNOWN; memcpy(buf, &s, sizeof(s)); memcpy(buf + sizeof(s), o_sig, o_sig_size); *sig = (struct vb2_signature *)buf; return VB2_SUCCESS; } static void show_usbpd1_stuff(const char *name, enum vb2_signature_algorithm sig_alg, enum vb2_hash_algorithm hash_alg, const uint8_t *o_pubkey, uint32_t o_pubkey_size) { struct vb2_public_key key; struct vb2_packed_key *pkey; uint8_t *sha1sum; int i; vb2_pubkey_from_usbpd1(&key, sig_alg, hash_alg, o_pubkey, o_pubkey_size); if (vb2_public_key_pack(&pkey, &key)) return; sha1sum = DigestBuf((uint8_t *)pkey + pkey->key_offset, pkey->key_size, SHA1_DIGEST_ALGORITHM); printf("USB-PD v1 image: %s\n", name); printf(" Algorithm: %s %s\n", vb2_lookup_by_num(vb2_text_vs_sig, sig_alg)->name, vb2_lookup_by_num(vb2_text_vs_hash, hash_alg)->name); printf(" Key sha1sum: "); for (i = 0; i < SHA1_DIGEST_SIZE; i++) printf("%02x", sha1sum[i]); printf("\n"); free(sha1sum); free(pkey); } /* Returns VB2_SUCCESS or random error code */ static int try_our_own(enum vb2_signature_algorithm sig_alg, enum vb2_hash_algorithm hash_alg, const uint8_t *o_pubkey, uint32_t o_pubkey_size, const uint8_t *o_sig, uint32_t o_sig_size, const uint8_t *data, uint32_t data_size) { struct vb2_public_key pubkey; struct vb2_signature *sig; uint8_t buf[VB2_WORKBUF_RECOMMENDED_SIZE] __attribute__ ((aligned (VB2_WORKBUF_ALIGN))); struct vb2_workbuf wb = { .buf = buf, .size = sizeof(buf), }; int rv = VB2_ERROR_UNKNOWN; vb2_pubkey_from_usbpd1(&pubkey, sig_alg, hash_alg, o_pubkey, o_pubkey_size); if ((rv = vb2_sig_from_usbpd1(&sig, sig_alg, hash_alg, o_sig, o_sig_size, data_size))) return rv; rv = vb2_verify_data(data, data_size, sig, &pubkey, &wb); free(sig); return rv; } /* Returns VB2_SUCCESS if the image validates itself */ static int check_self_consistency(const uint8_t *buf, const char *name, uint32_t ro_size, uint32_t rw_size, uint32_t ro_offset, uint32_t rw_offset, enum vb2_signature_algorithm sig_alg, enum vb2_hash_algorithm hash_alg) { /* Where are the important bits? */ uint32_t sig_size = vb2_rsa_sig_size(sig_alg); uint32_t sig_offset = rw_offset + rw_size - sig_size; uint32_t pubkey_size = usbpd1_packed_key_size(sig_alg); uint32_t pubkey_offset = ro_offset + ro_size - pubkey_size; int rv; /* Skip stuff that obviously doesn't work */ if (sig_size > rw_size || pubkey_size > ro_size) return VB2_ERROR_UNKNOWN; rv = try_our_own(sig_alg, hash_alg, /* algs */ buf + pubkey_offset, pubkey_size, /* pubkey blob */ buf + sig_offset, sig_size, /* sig blob */ buf + rw_offset, rw_size - sig_size); /* RW image */ if (rv == VB2_SUCCESS && name) show_usbpd1_stuff(name, sig_alg, hash_alg, buf + pubkey_offset, pubkey_size); return rv; } int ft_show_usbpd1(const char *name, uint8_t *buf, uint32_t len, void *data) { uint32_t ro_size, rw_size, ro_offset, rw_offset; int s, h; Debug("%s(): name %s\n", __func__, name); Debug("%s(): len 0x%08x (%d)\n", __func__, len, len); /* Get image locations */ if (!parse_size_opts(len, &ro_size, &rw_size, &ro_offset, &rw_offset)) return 1; /* TODO: If we don't have a RO image, ask for a public key * TODO: If we're given an external public key, use it (and its alg) */ if (!ro_size) { printf("Can't find the public key\n"); return 1; } /* TODO: Only loop through the numbers we haven't been given */ for (s = 0; s < ARRAY_SIZE(sigs); s++) for (h = 0; h < ARRAY_SIZE(hashes); h++) if (!check_self_consistency(buf, name, ro_size, rw_size, ro_offset, rw_offset, sigs[s], hashes[h])) return 0; printf("This doesn't appear to be a complete usbpd1 image\n"); return 1; }