void load_settings(struct settings *settings) { struct uci_context *ctx = uci_alloc_context(); if (!ctx) { fprintf(stderr, "autoupdater: error: failed to allocate UCI context\n"); abort(); } ctx->flags &= ~UCI_FLAG_STRICT; struct uci_package *p; struct uci_section *s; if (uci_load(ctx, "autoupdater", &p) != UCI_OK) { fputs("autoupdater: error: unable to load UCI package\n", stderr); exit(1); } s = uci_lookup_section(ctx, p, "settings"); if (!s || strcmp(s->type, "autoupdater")) { fputs("autoupdater: error: unable to load UCI settings\n", stderr); exit(1); } const char *enabled = uci_lookup_option_string(ctx, s, "enabled"); if ((!enabled || strcmp(enabled, "1")) && !settings->force) { fputs("autoupdater is disabled\n", stderr); exit(0); } const char *version_file = uci_lookup_option_string(ctx, s, "version_file"); if (version_file) settings->old_version = read_one_line(version_file); if (!settings->branch) settings->branch = uci_lookup_option_string(ctx, s, "branch"); if (!settings->branch) { fputs("autoupdater: error: no branch given in settings or command line\n", stderr); exit(1); } struct uci_section *branch = uci_lookup_section(ctx, p, settings->branch); if (!branch || strcmp(branch->type, "branch")) { fprintf(stderr, "autoupdater: error: unable to load branch configuration for branch '%s'\n", settings->branch); exit(1); } settings->good_signatures = load_positive_number(ctx, branch, "good_signatures"); if (settings->n_mirrors == 0) settings->mirrors = load_string_list(ctx, branch, "mirror", &settings->n_mirrors); const char **pubkeys_str = load_string_list(ctx, branch, "pubkey", &settings->n_pubkeys); settings->pubkeys = safe_malloc(settings->n_pubkeys * sizeof(ecc_25519_work_t)); size_t ignored_keys = 0; for (size_t i = 0; i < settings->n_pubkeys; i++) { ecc_int256_t pubkey_packed; if (!pubkeys_str[i]) goto pubkey_fail; if (!parsehex(pubkey_packed.p, pubkeys_str[i], 32)) goto pubkey_fail; if (!ecc_25519_load_packed_legacy(&settings->pubkeys[i-ignored_keys], &pubkey_packed)) goto pubkey_fail; if (!ecdsa_is_valid_pubkey(&settings->pubkeys[i-ignored_keys])) goto pubkey_fail; continue; pubkey_fail: fprintf(stderr, "autoupdater: warning: ignoring invalid public key %s\n", pubkeys_str[i]); ignored_keys++; } settings->n_pubkeys -= ignored_keys; /* Don't free UCI context, we still reference values from it */ }
int verify(const char *command, int argc, char **argv) { int ret = 1; unsigned char signature[sizeof(ecdsa_signature_t)]; set pubkeys, signatures; set_init(&pubkeys, sizeof(ecc_25519_work_t), 5); set_init(&signatures, sizeof(signature), 5); size_t min_good_signatures = 1; int opt; while ((opt = getopt(argc, argv, "s:p:n:")) != -1) { ecc_int256_t pubkey_packed; ecc_25519_work_t pubkey; switch (opt) { case 's': if (!parsehex(signature, optarg, sizeof(signature))) { fprintf(stderr, "Error while reading signature %s\n", optarg); break; } if (!set_add(&signatures, signature)) { fprintf(stderr, "Error in array_add\n"); goto out; } break; case 'p': if (!parsehex(pubkey_packed.p, optarg, 32)) { fprintf(stderr, "Error while reading pubkey %s\n", optarg); break; } int ok = ecc_25519_load_packed_legacy(&pubkey, &pubkey_packed); if (!ok || !ecdsa_is_valid_pubkey(&pubkey)) { fprintf(stderr, "Invalid pubkey %s\n", optarg); break; } if (!set_add(&pubkeys, &pubkey)) { fprintf(stderr, "Error in array_add\n"); goto out; } break; case 'n': min_good_signatures = atoi(optarg); } } if (optind > argc) { fprintf(stderr, "Usage: %s [-s signature ...] [-p pubkey ...] [-n num] file\n", command); goto out; } ecc_int256_t hash; if (!sha256_file((optind <= argc) ? argv[optind] : NULL, hash.p)) { fprintf(stderr, "Error while hashing file\n"); goto out; } { ecdsa_verify_context_t ctxs[signatures.size]; for (size_t i = 0; i < signatures.size; i++) ecdsa_verify_prepare_legacy(&ctxs[i], &hash, SET_INDEX(signatures, i)); size_t good_signatures = ecdsa_verify_list_legacy(ctxs, signatures.size, pubkeys.content, pubkeys.size); if (good_signatures >= min_good_signatures) ret = 0; } out: set_destroy(&pubkeys); set_destroy(&signatures); return ret; }
int main(int argc, char *argv[]) { unsigned char signature[64]; array pubkeys, signatures; array_init(&pubkeys, sizeof(ecc_25519_work_t), 5); array_init(&signatures, sizeof(signature), 5); int min_good_signatures = 1; int opt; while ((opt = getopt(argc, argv, "s:p:n:")) != -1) { ecc_int256_t pubkey_packed; ecc_25519_work_t pubkey; switch (opt) { case 's': if (!parsehex(signature, optarg, 64)) { fprintf(stderr, "Error while reading signature %s\n", optarg); break; } if (!array_add(&signatures, signature, sizeof(signature))) { fprintf(stderr, "Error in array_add\n"); goto error_out; } break; case 'p': if (!parsehex(pubkey_packed.p, optarg, 32)) { fprintf(stderr, "Error while reading pubkey %s\n", optarg); break; } int ret; ret = ecc_25519_load_packed(&pubkey, &pubkey_packed); if (!ret || !ecdsa_is_valid_pubkey(&pubkey)) { fprintf(stderr, "Invalid pubkey %s\n", optarg); break; } if (!array_add(&pubkeys, &pubkey, sizeof(ecc_25519_work_t))) { fprintf(stderr, "Error in array_add\n"); goto error_out; } break; case 'n': min_good_signatures = atoi(optarg); } } if (optind >= argc) { fprintf(stderr, "Usage: %s [-s signature ...] [-p pubkey ...] [-n num] file\n", argv[0]); goto error_out; } ecc_int256_t hash; if (!sha256_file(argv[optind], hash.p)) { fprintf(stderr, "Error while hashing file\n"); goto error_out; } int good_signatures = 0; array_nub(&pubkeys); array_nub(&signatures); for (int i = 0; i < signatures.size; i++) { unsigned char *signature; ecdsa_verify_context ctx; signature = ARRAY_INDEX(signatures, i); ecdsa_verify_prepare(&ctx, &hash, signature); for (int i = 0; i < pubkeys.size; i++) { ecc_25519_work_t *pubkey; pubkey = ARRAY_INDEX(pubkeys, i); if (ecdsa_verify_with_pubkey(&ctx, pubkey)) { good_signatures++; array_rm(&pubkeys, i); break; } } } array_destroy(&pubkeys); array_destroy(&signatures); if (good_signatures >= min_good_signatures) return 0; return 1; error_out: array_destroy(&pubkeys); array_destroy(&signatures); return 1; }