diff --git a/src/Makefile b/src/Makefile index e2b40ba..6b1b237 100644 --- a/src/Makefile +++ b/src/Makefile @@ -19,9 +19,8 @@ ZLIB_LIBS := $(shell $(PKG_CONFIG) --libs zlib) libapk_soname := 3.12.0 libapk_so := $(obj)/libapk.so.$(libapk_soname) libapk.so.$(libapk_soname)-objs := \ - adb.o adb_trust.o \ - common.o context.o database.o package.o commit.o solver.o \ - version.o atom.o blob.o hash.o print.o \ + adb.o common.o context.o database.o package.o commit.o solver.o \ + trust.o version.o atom.o blob.o hash.o print.o \ io.o io_url.o io_gunzip.o io_archive.o libapk.so.$(libapk_soname)-libs := libfetch/libfetch.a diff --git a/src/adb.c b/src/adb.c index 848322e..44b3589 100644 --- a/src/adb.c +++ b/src/adb.c @@ -6,9 +6,12 @@ #include #include #include +#include +#include #include "adb.h" #include "apk_blob.h" +#include "apk_trust.h" /* Block enumeration */ static inline struct adb_block *adb_block_validate(struct adb_block *blk, apk_blob_t b) @@ -60,7 +63,7 @@ void adb_reset(struct adb *db) db->adb.len = 0; } -static int __adb_m_parse(struct adb *db, struct adb_trust *t) +static int __adb_m_parse(struct adb *db, struct apk_trust *t) { struct adb_verify_ctx vfy = {}; struct adb_block *blk; @@ -95,13 +98,13 @@ static int __adb_m_parse(struct adb *db, struct adb_trust *t) return r; } -int adb_m_blob(struct adb *db, apk_blob_t blob, struct adb_trust *t) +int adb_m_blob(struct adb *db, apk_blob_t blob, struct apk_trust *t) { *db = (struct adb) { .data = blob }; return __adb_m_parse(db, t); } -int adb_m_map(struct adb *db, int fd, uint32_t expected_schema, struct adb_trust *t) +int adb_m_map(struct adb *db, int fd, uint32_t expected_schema, struct apk_trust *t) { struct stat st; struct adb_header *hdr; @@ -810,7 +813,7 @@ int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_ist return r; } -int adb_c_create(struct apk_ostream *os, struct adb *db, struct adb_trust *t) +int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t) { if (IS_ERR(os)) return PTR_ERR(os); if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC)) { @@ -824,6 +827,117 @@ ret: return apk_ostream_close(os); } +/* Signatures */ +static int adb_verify_ctx_calc(struct adb_verify_ctx *vfy, unsigned int hash_alg, apk_blob_t data, apk_blob_t *pmd) +{ + const EVP_MD *evp; + apk_blob_t md; + + switch (hash_alg) { + case ADB_HASH_SHA512: + evp = EVP_sha512(); + *pmd = md = APK_BLOB_BUF(vfy->sha512); + break; + default: + return -ENOTSUP; + } + + if (!(vfy->calc & (1 << hash_alg))) { + unsigned int sz = md.len; + if (APK_BLOB_IS_NULL(data)) return -ENOMSG; + if (EVP_Digest(data.ptr, data.len, (unsigned char*) md.ptr, &sz, evp, NULL) != 1 || + sz != md.len) + return -EIO; + vfy->calc |= (1 << hash_alg); + } + return 0; +} + +int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, struct apk_ostream *os) +{ + union { + struct adb_sign_hdr hdr; + struct adb_sign_v0 v0; + unsigned char buf[8192]; + } sig; + struct apk_trust_key *tkey; + apk_blob_t md; + size_t siglen; + int r; + + if (!vfy) { + vfy = alloca(sizeof *vfy); + memset(vfy, 0, sizeof *vfy); + } + + r = adb_verify_ctx_calc(vfy, ADB_HASH_SHA512, db->adb, &md); + if (r) return r; + + list_for_each_entry(tkey, &trust->private_key_list, key_node) { + sig.v0 = (struct adb_sign_v0) { + .hdr.sign_ver = 0, + .hdr.hash_alg = ADB_HASH_SHA512, + }; + memcpy(sig.v0.id, tkey->key.id, sizeof(sig.v0.id)); + + siglen = sizeof sig.buf - sizeof sig.v0; + EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL); + if (EVP_DigestSignInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 || + EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 || + EVP_DigestUpdate(trust->mdctx, &sig.hdr.sign_ver, sizeof sig.hdr.sign_ver) != 1 || + EVP_DigestUpdate(trust->mdctx, &sig.hdr.hash_alg, sizeof sig.hdr.hash_alg) != 1 || + EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 || + EVP_DigestSignFinal(trust->mdctx, sig.v0.sig, &siglen) != 1) { + ERR_print_errors_fp(stdout); + goto err_io; + } + + r = adb_c_block(os, ADB_BLOCK_SIG, APK_BLOB_PTR_LEN((char*) &sig, sizeof(sig.v0) + siglen)); + if (r < 0) goto err; + } + return 0; +err_io: + r = -EIO; +err: + apk_ostream_cancel(os, r); + return r; +} + +int adb_trust_verify_signature(struct apk_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, apk_blob_t sigb) +{ + struct apk_trust_key *tkey; + struct adb_sign_hdr *sig; + struct adb_sign_v0 *sig0; + apk_blob_t md; + + if (APK_BLOB_IS_NULL(db->adb)) return -ENOMSG; + if (sigb.len < sizeof(struct adb_sign_hdr)) return -EBADMSG; + + sig = (struct adb_sign_hdr *) sigb.ptr; + sig0 = (struct adb_sign_v0 *) sigb.ptr; + if (sig->sign_ver != 0) return -ENOSYS; + + list_for_each_entry(tkey, &trust->trusted_key_list, key_node) { + if (memcmp(sig0->id, tkey->key.id, sizeof sig0->id) != 0) continue; + if (adb_verify_ctx_calc(vfy, sig->hash_alg, db->adb, &md) != 0) continue; + + EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL); + if (EVP_DigestVerifyInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 || + EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 || + EVP_DigestUpdate(trust->mdctx, &sig->sign_ver, sizeof sig->sign_ver) != 1 || + EVP_DigestUpdate(trust->mdctx, &sig->hash_alg, sizeof sig->hash_alg) != 1 || + EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 || + EVP_DigestVerifyFinal(trust->mdctx, sig0->sig, sigb.len - sizeof(*sig0)) != 1) { + ERR_clear_error(); + continue; + } + + return 0; + } + + return -EKEYREJECTED; +} + /* Container transformation interface */ int adb_c_xfrm(struct adb_xfrm *x, int (*cb)(struct adb_xfrm *, struct adb_block *, struct apk_istream *)) { diff --git a/src/adb.h b/src/adb.h index e4c2035..413ef36 100644 --- a/src/adb.h +++ b/src/adb.h @@ -5,10 +5,10 @@ #include #include #include "apk_io.h" +#include "apk_trust.h" struct adb; struct adb_obj; -struct adb_trust; struct adb_verify_ctx; typedef uint32_t adb_val_t; @@ -154,8 +154,8 @@ struct adb_obj { int adb_free(struct adb *); void adb_reset(struct adb *); -int adb_m_blob(struct adb *, apk_blob_t, struct adb_trust *); -int adb_m_map(struct adb *, int fd, uint32_t expected_schema, struct adb_trust *); +int adb_m_blob(struct adb *, apk_blob_t, struct apk_trust *); +int adb_m_map(struct adb *, int fd, uint32_t expected_schema, struct apk_trust *); #define adb_w_init_alloca(db, schema, num_buckets) adb_w_init_dynamic(db, schema, alloca(sizeof(struct list_head[num_buckets])), num_buckets) #define adb_w_init_tmp(db, size) adb_w_init_static(db, alloca(size), size) int adb_w_init_dynamic(struct adb *db, uint32_t schema, void *buckets, size_t num_buckets); @@ -216,35 +216,16 @@ int adb_s_field_by_name(const struct adb_object_schema *, const char *); int adb_c_header(struct apk_ostream *os, struct adb *db); int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t); int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_istream *is, struct adb_verify_ctx *); -int adb_c_create(struct apk_ostream *os, struct adb *db, struct adb_trust *t); +int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t); /* Trust */ -#include - -struct adb_pkey { - uint8_t id[16]; - EVP_PKEY *key; -}; - -int adb_pkey_init(struct adb_pkey *pkey, EVP_PKEY *key); -void adb_pkey_free(struct adb_pkey *pkey); -int adb_pkey_load(struct adb_pkey *pkey, int dirfd, const char *fn); - -struct adb_trust { - EVP_MD_CTX *mdctx; - struct list_head trusted_key_list; - struct list_head private_key_list; -}; - struct adb_verify_ctx { uint32_t calc; uint8_t sha512[64]; }; -int adb_trust_init(struct adb_trust *trust, int keysfd, struct apk_string_array *); -void adb_trust_free(struct adb_trust *trust); -int adb_trust_write_signatures(struct adb_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, struct apk_ostream *os); -int adb_trust_verify_signature(struct adb_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, apk_blob_t sigb); +int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, struct apk_ostream *os); +int adb_trust_verify_signature(struct apk_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, apk_blob_t sigb); /* Transform existing file */ struct adb_xfrm { diff --git a/src/adb_trust.c b/src/adb_trust.c deleted file mode 100644 index 4f08441..0000000 --- a/src/adb_trust.c +++ /dev/null @@ -1,266 +0,0 @@ -#include -#include -#include -#include -#include -#include "apk_defines.h" -#include "adb.h" - -struct adb_trust_key { - struct list_head key_node; - struct adb_pkey key; - -}; - -/* Trust */ -int adb_pkey_init(struct adb_pkey *pkey, EVP_PKEY *key) -{ - unsigned char dig[EVP_MAX_MD_SIZE], *pub = NULL; - unsigned int dlen = sizeof dig; - int len; - - if ((len = i2d_PublicKey(key, &pub)) < 0) return -EIO; - EVP_Digest(pub, len, dig, &dlen, EVP_sha512(), NULL); - memcpy(pkey->id, dig, sizeof pkey->id); - OPENSSL_free(pub); - - pkey->key = key; - return 0; -} - -void adb_pkey_free(struct adb_pkey *pkey) -{ - EVP_PKEY_free(pkey->key); -} - -int adb_pkey_load(struct adb_pkey *pkey, int dirfd, const char *fn) -{ - EVP_PKEY *key; - BIO *bio; - int fd; - - fd = openat(dirfd, fn, O_RDONLY|O_CLOEXEC); - if (fd < 0) return -errno; - - bio = BIO_new_fp(fdopen(fd, "r"), BIO_CLOSE); - if (!bio) return -ENOMEM; - - key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); - if (!key) { - BIO_reset(bio); - key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - } - ERR_clear_error(); - - BIO_free(bio); - if (!key) return -EBADMSG; - - adb_pkey_init(pkey, key); - return 0; -} - -static struct adb_trust_key *adb_trust_load_key(int dirfd, const char *filename) -{ - struct adb_trust_key *key; - int r; - - key = calloc(1, sizeof *key); - if (!key) return ERR_PTR(-ENOMEM); - - r = adb_pkey_load(&key->key, dirfd, filename); - if (r) { - free(key); - return ERR_PTR(-ENOKEY); - } - - list_init(&key->key_node); - return key; -} - -static int __adb_trust_load_pubkey(void *pctx, int dirfd, const char *filename) -{ - struct adb_trust *trust = pctx; - struct adb_trust_key *key = adb_trust_load_key(dirfd, filename); - - if (!IS_ERR(key)) - list_add_tail(&key->key_node, &trust->trusted_key_list); - - return 0; -} - -int adb_trust_init(struct adb_trust *trust, int dirfd, struct apk_string_array *pkey_files) -{ - char **fn; - - *trust = (struct adb_trust){ - .mdctx = EVP_MD_CTX_new(), - }; - if (!trust->mdctx) return -ENOMEM; - EVP_MD_CTX_set_flags(trust->mdctx, EVP_MD_CTX_FLAG_FINALISE); - list_init(&trust->trusted_key_list); - list_init(&trust->private_key_list); - apk_dir_foreach_file(dirfd, __adb_trust_load_pubkey, trust); - - foreach_array_item(fn, pkey_files) { - struct adb_trust_key *key = adb_trust_load_key(AT_FDCWD, *fn); - if (IS_ERR(key)) return PTR_ERR(key); - list_add_tail(&key->key_node, &trust->private_key_list); - } - - return 0; -} - -static void __adb_trust_free_keys(struct list_head *h) -{ - struct adb_trust_key *tkey, *n; - - list_for_each_entry_safe(tkey, n, h, key_node) { - list_del(&tkey->key_node); - adb_pkey_free(&tkey->key); - free(tkey); - } -} - -void adb_trust_free(struct adb_trust *trust) -{ - if (!trust->mdctx) return; - __adb_trust_free_keys(&trust->trusted_key_list); - __adb_trust_free_keys(&trust->private_key_list); - EVP_MD_CTX_free(trust->mdctx); -} - -static int adb_verify_ctx_calc(struct adb_verify_ctx *vfy, unsigned int hash_alg, apk_blob_t data, apk_blob_t *pmd) -{ - const EVP_MD *evp; - apk_blob_t md; - - switch (hash_alg) { - case ADB_HASH_SHA512: - evp = EVP_sha512(); - *pmd = md = APK_BLOB_BUF(vfy->sha512); - break; - default: - return -ENOTSUP; - } - - if (!(vfy->calc & (1 << hash_alg))) { - unsigned int sz = md.len; - if (APK_BLOB_IS_NULL(data)) return -ENOMSG; - if (EVP_Digest(data.ptr, data.len, (unsigned char*) md.ptr, &sz, evp, NULL) != 1 || - sz != md.len) - return -EIO; - vfy->calc |= (1 << hash_alg); - } - return 0; -} - -int adb_trust_write_signatures(struct adb_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, struct apk_ostream *os) -{ - union { - struct adb_sign_hdr hdr; - struct adb_sign_v0 v0; - unsigned char buf[8192]; - } sig; - struct adb_trust_key *tkey; - apk_blob_t md; - size_t siglen; - int r; - - if (!vfy) { - vfy = alloca(sizeof *vfy); - memset(vfy, 0, sizeof *vfy); - } - - r = adb_verify_ctx_calc(vfy, ADB_HASH_SHA512, db->adb, &md); - if (r) return r; - - list_for_each_entry(tkey, &trust->private_key_list, key_node) { - sig.v0 = (struct adb_sign_v0) { - .hdr.sign_ver = 0, - .hdr.hash_alg = ADB_HASH_SHA512, - }; - memcpy(sig.v0.id, tkey->key.id, sizeof(sig.v0.id)); - - siglen = sizeof sig.buf - sizeof sig.v0; - EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL); - if (EVP_DigestSignInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 || - EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 || - EVP_DigestUpdate(trust->mdctx, &sig.hdr.sign_ver, sizeof sig.hdr.sign_ver) != 1 || - EVP_DigestUpdate(trust->mdctx, &sig.hdr.hash_alg, sizeof sig.hdr.hash_alg) != 1 || - EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 || - EVP_DigestSignFinal(trust->mdctx, sig.v0.sig, &siglen) != 1) { - ERR_print_errors_fp(stdout); - goto err_io; - } - - r = adb_c_block(os, ADB_BLOCK_SIG, APK_BLOB_PTR_LEN((char*) &sig, sizeof(sig.v0) + siglen)); - if (r < 0) goto err; - } - return 0; -err_io: - r = -EIO; -err: - apk_ostream_cancel(os, r); - return r; -} - -int adb_trust_verify_signature(struct adb_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, apk_blob_t sigb) -{ - struct adb_trust_key *tkey; - struct adb_sign_hdr *sig; - struct adb_sign_v0 *sig0; - apk_blob_t md; - - if (APK_BLOB_IS_NULL(db->adb)) return -ENOMSG; - if (sigb.len < sizeof(struct adb_sign_hdr)) return -EBADMSG; - - sig = (struct adb_sign_hdr *) sigb.ptr; - sig0 = (struct adb_sign_v0 *) sigb.ptr; - if (sig->sign_ver != 0) return -ENOSYS; - - list_for_each_entry(tkey, &trust->trusted_key_list, key_node) { - if (memcmp(sig0->id, tkey->key.id, sizeof sig0->id) != 0) continue; - if (adb_verify_ctx_calc(vfy, sig->hash_alg, db->adb, &md) != 0) continue; - - EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL); - if (EVP_DigestVerifyInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 || - EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 || - EVP_DigestUpdate(trust->mdctx, &sig->sign_ver, sizeof sig->sign_ver) != 1 || - EVP_DigestUpdate(trust->mdctx, &sig->hash_alg, sizeof sig->hash_alg) != 1 || - EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 || - EVP_DigestVerifyFinal(trust->mdctx, sig0->sig, sigb.len - sizeof(*sig0)) != 1) { - ERR_clear_error(); - continue; - } - - return 0; - } - - return -EKEYREJECTED; -} - -/* Command group for signing */ - -#include "apk_applet.h" - -#define SIGNING_OPTIONS(OPT) \ - OPT(OPT_SIGN_sign_key, APK_OPT_ARG "sign-key") - -APK_OPT_GROUP(options_signing, "Signing", SIGNING_OPTIONS); - -static int option_parse_signing(void *ctx, struct apk_ctx *ac, int optch, const char *optarg) -{ - switch (optch) { - case OPT_SIGN_sign_key: - *apk_string_array_add(&ac->private_keys) = (char*) optarg; - break; - default: - return -ENOTSUP; - } - return 0; -} - -const struct apk_option_group optgroup_signing = { - .desc = options_signing, - .parse = option_parse_signing, -}; diff --git a/src/apk_context.h b/src/apk_context.h index 41cc361..8f7ca5e 100644 --- a/src/apk_context.h +++ b/src/apk_context.h @@ -10,6 +10,7 @@ #define APK_CONTEXT_H #include "apk_print.h" +#include "apk_trust.h" #include "apk_io.h" #include "adb.h" @@ -65,18 +66,17 @@ struct apk_ctx { struct apk_string_array *repository_list; struct apk_string_array *private_keys; - struct adb_trust trust; + struct apk_trust trust; struct apk_id_cache id_cache; struct apk_database *db; - int root_fd, keys_fd; + int root_fd; }; void apk_ctx_init(struct apk_ctx *ac); void apk_ctx_free(struct apk_ctx *ac); int apk_ctx_prepare(struct apk_ctx *ac); -int apk_ctx_fd_keys(struct apk_ctx *ac); -struct adb_trust *apk_ctx_get_trust(struct apk_ctx *ac); +struct apk_trust *apk_ctx_get_trust(struct apk_ctx *ac); struct apk_id_cache *apk_ctx_get_id_cache(struct apk_ctx *ac); static inline int apk_ctx_fd_root(struct apk_ctx *ac) { return ac->root_fd; } diff --git a/src/apk_database.h b/src/apk_database.h index 7373b99..94507bc 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -129,7 +129,7 @@ struct apk_repository_tag { struct apk_database { struct apk_ctx *ctx; - int root_fd, lock_fd, cache_fd, keys_fd; + int root_fd, lock_fd, cache_fd; unsigned num_repos, num_repo_tags; const char *cache_dir; char *cache_remount_dir, *root_proc_dir; diff --git a/src/apk_package.h b/src/apk_package.h index 6fbf0c7..0f7542c 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -18,6 +18,7 @@ struct apk_database; struct apk_name; struct apk_provider; +struct apk_trust; #define APK_SCRIPT_INVALID -1 #define APK_SCRIPT_PRE_INSTALL 0 @@ -45,7 +46,7 @@ struct apk_provider; #define APK_FOREACH_GENID_MASK 0xffffff00 struct apk_sign_ctx { - int keys_fd; + struct apk_trust *trust; int action; const EVP_MD *md; int num_signatures; @@ -132,7 +133,7 @@ APK_ARRAY(apk_package_array, struct apk_package *); extern const char *apk_script_types[]; void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action, - struct apk_checksum *identity, int keys_fd, int allow_untrusted); + struct apk_checksum *identity, struct apk_trust *trust); void apk_sign_ctx_free(struct apk_sign_ctx *ctx); int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, const struct apk_file_info *fi, diff --git a/src/app_adbdump.c b/src/app_adbdump.c index c101752..40da2c5 100644 --- a/src/app_adbdump.c +++ b/src/app_adbdump.c @@ -7,7 +7,7 @@ struct adb_dump_ctx { struct adb *db; - struct adb_trust *trust; + struct apk_trust *trust; char prefix[128], *pfx; }; @@ -203,7 +203,7 @@ static void dump_adb(struct adb_dump_ctx *ctx) if (IS_ERR(blk)) fprintf(stdout, "%s# block enumeration error: corrupt data area\n", ctx->prefix); } -static int mmap_and_dump_adb(struct adb_trust *trust, int fd) +static int mmap_and_dump_adb(struct apk_trust *trust, int fd) { struct adb db; struct adb_dump_ctx ctx = { diff --git a/src/app_adbsign.c b/src/app_adbsign.c index 120f702..cdfd6e9 100644 --- a/src/app_adbsign.c +++ b/src/app_adbsign.c @@ -41,7 +41,7 @@ static const struct apk_option_group optgroup_applet = { static int update_signatures(struct adb_xfrm *xfrm, struct adb_block *blk, struct apk_istream *is) { struct sign_ctx *ctx = container_of(xfrm, struct sign_ctx, xfrm); - struct adb_trust *trust = apk_ctx_get_trust(ctx->ac); + struct apk_trust *trust = apk_ctx_get_trust(ctx->ac); int r; switch (blk ? ADB_BLOCK_TYPE(blk) : -1) { diff --git a/src/app_add.c b/src/app_add.c index 42e4cd9..655d2d1 100644 --- a/src/app_add.c +++ b/src/app_add.c @@ -159,7 +159,7 @@ static int add_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *args return -1; apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY_AND_GENERATE, - NULL, db->keys_fd, db->ctx->flags & APK_ALLOW_UNTRUSTED); + NULL, apk_ctx_get_trust(ac)); r = apk_pkg_read(db, *parg, &sctx, &pkg); apk_sign_ctx_free(&sctx); if (r != 0) { diff --git a/src/app_convndx.c b/src/app_convndx.c index 9f687ac..3014e11 100644 --- a/src/app_convndx.c +++ b/src/app_convndx.c @@ -52,16 +52,15 @@ static int load_apkindex(void *sctx, const struct apk_file_info *fi, static int load_index(struct conv_ctx *ctx, struct apk_istream *is) { - struct apk_id_cache *idc = apk_ctx_get_id_cache(ctx->ac); int r = 0; if (IS_ERR_OR_NULL(is)) return is ? PTR_ERR(is) : -EINVAL; ctx->found = 0; - apk_sign_ctx_init(&ctx->sctx, APK_SIGN_VERIFY, NULL, apk_ctx_fd_keys(ctx->ac), ctx->ac->flags & APK_ALLOW_UNTRUSTED); + apk_sign_ctx_init(&ctx->sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(ctx->ac)); r = apk_tar_parse( apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx->sctx), - load_apkindex, ctx, idc); + load_apkindex, ctx, apk_ctx_get_id_cache(ctx->ac)); apk_sign_ctx_free(&ctx->sctx); if (r >= 0 && ctx->found == 0) r = -ENOMSG; @@ -72,7 +71,7 @@ static int conv_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *ar { char **arg; struct conv_ctx *ctx = pctx; - struct adb_trust *trust = apk_ctx_get_trust(ac); + struct apk_trust *trust = apk_ctx_get_trust(ac); struct adb_obj ndx; int r; diff --git a/src/app_index.c b/src/app_index.c index 896474b..5881e56 100644 --- a/src/app_index.c +++ b/src/app_index.c @@ -186,7 +186,7 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar if (!found) { struct apk_sign_ctx sctx; - apk_sign_ctx_init(&sctx, ictx->method, NULL, db->keys_fd, db->ctx->flags & APK_ALLOW_UNTRUSTED); + apk_sign_ctx_init(&sctx, ictx->method, NULL, apk_ctx_get_trust(ac)); r = apk_pkg_read(db, *parg, &sctx, &pkg); if (r < 0) { apk_err(out, "%s: %s", *parg, apk_error_str(r)); diff --git a/src/app_manifest.c b/src/app_manifest.c index 19d02f4..6f32a92 100644 --- a/src/app_manifest.c +++ b/src/app_manifest.c @@ -110,7 +110,7 @@ static void process_file(struct apk_database *db, const char *match) ctx.prefix2 = ": "; } - apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd, db->ctx->flags & APK_ALLOW_UNTRUSTED); + apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx)); r = apk_tar_parse( apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, match), apk_sign_ctx_mpart_cb, &sctx), read_file_entry, &ctx, idc); diff --git a/src/app_mkndx.c b/src/app_mkndx.c index 2dc6f81..8c29ce6 100644 --- a/src/app_mkndx.c +++ b/src/app_mkndx.c @@ -190,7 +190,7 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a { struct apk_out *out = &ac->out; struct apk_id_cache *idc = apk_ctx_get_id_cache(ac); - struct adb_trust *trust = apk_ctx_get_trust(ac); + struct apk_trust *trust = apk_ctx_get_trust(ac); struct adb odb, tmpdb; struct adb_obj oroot, opkgs, ndx, tmpl; struct apk_file_info fi; @@ -276,7 +276,7 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a } if (!found) { do_file: - apk_sign_ctx_init(&ctx->sctx, APK_SIGN_VERIFY, NULL, apk_ctx_fd_keys(ac), ac->flags & APK_ALLOW_UNTRUSTED); + apk_sign_ctx_init(&ctx->sctx, APK_SIGN_VERIFY, NULL, trust); r = apk_tar_parse( apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, *parg), apk_sign_ctx_mpart_cb, &ctx->sctx), mkndx_parse_v2_tar, ctx, idc); diff --git a/src/app_verify.c b/src/app_verify.c index e36f3e9..edec6c9 100644 --- a/src/app_verify.c +++ b/src/app_verify.c @@ -20,11 +20,14 @@ static int verify_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *a struct apk_out *out = &ac->out; struct apk_sign_ctx sctx; struct apk_id_cache *idc = apk_ctx_get_id_cache(ac); + struct apk_trust *trust = apk_ctx_get_trust(ac); char **parg; int r, ok, rc = 0; + trust->allow_untrusted = 1; + foreach_array_item(parg, args) { - apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, apk_ctx_fd_keys(ac), 1); + apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, trust); r = apk_tar_parse( apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, *parg), apk_sign_ctx_mpart_cb, &sctx), diff --git a/src/app_version.c b/src/app_version.c index a42ab63..4dfbf35 100644 --- a/src/app_version.c +++ b/src/app_version.c @@ -86,7 +86,7 @@ static int option_parse_applet(void *ctx, struct apk_ctx *ac, int opt, const cha break; case OPT_VERSION_check: ictx->action = ver_validate; - ac->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS; + ac->open_flags = 0; break; case OPT_VERSION_indexes: ictx->action = ver_indexes; @@ -96,7 +96,7 @@ static int option_parse_applet(void *ctx, struct apk_ctx *ac, int opt, const cha break; case OPT_VERSION_test: ictx->action = ver_test; - ac->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS; + ac->open_flags = 0; break; default: return -ENOTSUP; diff --git a/src/context.c b/src/context.c index 6f953b0..784f082 100644 --- a/src/context.c +++ b/src/context.c @@ -26,7 +26,7 @@ void apk_ctx_init(struct apk_ctx *ac) void apk_ctx_free(struct apk_ctx *ac) { apk_id_cache_free(&ac->id_cache); - adb_trust_free(&ac->trust); + apk_trust_free(&ac->trust); apk_string_array_free(&ac->repository_list); apk_string_array_free(&ac->private_keys); } @@ -55,17 +55,14 @@ int apk_ctx_prepare(struct apk_ctx *ac) return 0; } -int apk_ctx_fd_keys(struct apk_ctx *ac) -{ - if (ac->keys_fd <= 0) ac->keys_fd = openat(ac->root_fd, ac->keys_dir, O_RDONLY | O_CLOEXEC); - return ac->keys_fd; -} - -struct adb_trust *apk_ctx_get_trust(struct apk_ctx *ac) +struct apk_trust *apk_ctx_get_trust(struct apk_ctx *ac) { if (!ac->trust.mdctx) { - int r = adb_trust_init(&ac->trust, dup(apk_ctx_fd_keys(ac)), ac->private_keys); + int r = apk_trust_init(&ac->trust, + openat(ac->root_fd, ac->keys_dir, O_RDONLY | O_CLOEXEC), + ac->private_keys); if (r) return ERR_PTR(r); + ac->trust.allow_untrusted = !!(ac->flags & APK_ALLOW_UNTRUSTED); } return &ac->trust; } diff --git a/src/database.c b/src/database.c index 5fd1c82..bbcbb9d 100644 --- a/src/database.c +++ b/src/database.c @@ -638,7 +638,7 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo, if (cb) cb(cb_ctx, 0); if (verify != APK_SIGN_NONE) { - apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd, db->ctx->flags & APK_ALLOW_UNTRUSTED); + apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx)); is = apk_istream_from_url(url, apk_db_url_since(db, st.st_mtime)); is = apk_istream_tee(is, db->cache_fd, tmpcacheitem, !autoupdate, cb, cb_ctx); is = apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx); @@ -1645,8 +1645,6 @@ int apk_db_open(struct apk_database *db, struct apk_ctx *ac) } } - db->keys_fd = openat(db->root_fd, ac->keys_dir, O_RDONLY | O_CLOEXEC); - if (db->ctx->flags & APK_OVERLAY_FROM_STDIN) { db->ctx->flags &= ~APK_OVERLAY_FROM_STDIN; apk_db_read_overlay(db, apk_istream_from_fd(STDIN_FILENO)); @@ -1810,7 +1808,6 @@ void apk_db_close(struct apk_database *db) db->cache_remount_dir = NULL; } - if (db->keys_fd) close(db->keys_fd); if (db->cache_fd) close(db->cache_fd); if (db->lock_fd) close(db->lock_fd); } @@ -2165,7 +2162,7 @@ static int load_index(struct apk_database *db, struct apk_istream *is, ctx.db = db; ctx.repo = repo; ctx.found = 0; - apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL, db->keys_fd, db->ctx->flags & APK_ALLOW_UNTRUSTED); + apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx)); r = apk_tar_parse(apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx.sctx), load_apkindex, &ctx, db->id_cache); apk_sign_ctx_free(&ctx.sctx); @@ -2793,7 +2790,7 @@ static int apk_db_unpack_pkg(struct apk_database *db, .cb = cb, .cb_ctx = cb_ctx, }; - apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &pkg->csum, db->keys_fd, db->ctx->flags & APK_ALLOW_UNTRUSTED); + apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &pkg->csum, apk_ctx_get_trust(db->ctx)); r = apk_tar_parse(apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx.sctx), apk_db_install_archive_entry, &ctx, db->id_cache); apk_sign_ctx_free(&ctx.sctx); diff --git a/src/meson.build b/src/meson.build index 4f3d435..bacad3d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,7 +1,6 @@ libapk_so_version = '2.99.0' libapk_src = [ 'adb.c', - 'adb_trust.c', 'apk_adb.c', 'atom.c', 'blob.c', @@ -17,6 +16,7 @@ libapk_src = [ 'package.c', 'print.c', 'solver.c', + 'trust.c', 'version.c', ] diff --git a/src/package.c b/src/package.c index b9fcc34..5f0e88a 100644 --- a/src/package.c +++ b/src/package.c @@ -465,13 +465,12 @@ int apk_script_type(const char *name) } void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action, - struct apk_checksum *identity, int keys_fd, - int allow_untrusted) + struct apk_checksum *identity, struct apk_trust *trust) { memset(ctx, 0, sizeof(struct apk_sign_ctx)); - ctx->keys_fd = keys_fd; + ctx->trust = trust; ctx->action = action; - ctx->allow_untrusted = !!allow_untrusted; + ctx->allow_untrusted = trust->allow_untrusted; switch (action) { case APK_SIGN_VERIFY: /* If we're only verifing, we're going to start with a @@ -505,8 +504,6 @@ void apk_sign_ctx_free(struct apk_sign_ctx *ctx) { if (ctx->signature.data.ptr != NULL) free(ctx->signature.data.ptr); - if (ctx->signature.pkey != NULL) - EVP_PKEY_free(ctx->signature.pkey); EVP_MD_CTX_free(ctx->mdctx); } @@ -539,8 +536,8 @@ int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, }; const EVP_MD *md = NULL; const char *name = NULL; - BIO *bio; - int r, i, fd; + struct apk_pkey *pkey; + int r, i; if (ctx->data_started) return 1; @@ -580,9 +577,6 @@ int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, ctx->signature.pkey != NULL) return 0; - if (ctx->keys_fd < 0) - return 0; - for (i = 0; i < ARRAY_SIZE(signature_type); i++) { size_t slen = strlen(signature_type[i].type); if (strncmp(&fi->name[6], signature_type[i].type, slen) == 0 && @@ -594,17 +588,12 @@ int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, } if (!md) return 0; - fd = openat(ctx->keys_fd, name, O_RDONLY|O_CLOEXEC); - if (fd < 0) return 0; - - bio = BIO_new_fp(fdopen(fd, "r"), BIO_CLOSE); - ctx->signature.pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); - if (ctx->signature.pkey != NULL) { + pkey = apk_trust_key_by_name(ctx->trust, name); + if (pkey) { ctx->md = md; + ctx->signature.pkey = pkey->key; ctx->signature.data = apk_blob_from_istream(is, fi->size); } - BIO_free(bio); - return 0; } diff --git a/src/trust.c b/src/trust.c new file mode 100644 index 0000000..6f63137 --- /dev/null +++ b/src/trust.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include + +#include "apk_defines.h" +#include "apk_trust.h" +#include "apk_io.h" + +/* Trust */ +int apk_pkey_init(struct apk_pkey *pkey, EVP_PKEY *key) +{ + unsigned char dig[EVP_MAX_MD_SIZE], *pub = NULL; + unsigned int dlen = sizeof dig; + int len; + + if ((len = i2d_PublicKey(key, &pub)) < 0) return -EIO; + EVP_Digest(pub, len, dig, &dlen, EVP_sha512(), NULL); + memcpy(pkey->id, dig, sizeof pkey->id); + OPENSSL_free(pub); + + pkey->key = key; + return 0; +} + +void apk_pkey_free(struct apk_pkey *pkey) +{ + EVP_PKEY_free(pkey->key); +} + +int apk_pkey_load(struct apk_pkey *pkey, int dirfd, const char *fn) +{ + EVP_PKEY *key; + BIO *bio; + int fd; + + fd = openat(dirfd, fn, O_RDONLY|O_CLOEXEC); + if (fd < 0) return -errno; + + bio = BIO_new_fp(fdopen(fd, "r"), BIO_CLOSE); + if (!bio) return -ENOMEM; + + key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (!key) { + BIO_reset(bio); + key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + } + ERR_clear_error(); + + BIO_free(bio); + if (!key) return -EBADMSG; + + apk_pkey_init(pkey, key); + return 0; +} + +static struct apk_trust_key *apk_trust_load_key(int dirfd, const char *filename) +{ + struct apk_trust_key *key; + int r; + + key = calloc(1, sizeof *key); + if (!key) return ERR_PTR(-ENOMEM); + + r = apk_pkey_load(&key->key, dirfd, filename); + if (r) { + free(key); + return ERR_PTR(-ENOKEY); + } + + list_init(&key->key_node); + key->filename = strdup(filename); + return key; +} + +static int __apk_trust_load_pubkey(void *pctx, int dirfd, const char *filename) +{ + struct apk_trust *trust = pctx; + struct apk_trust_key *key = apk_trust_load_key(dirfd, filename); + + if (!IS_ERR(key)) + list_add_tail(&key->key_node, &trust->trusted_key_list); + + return 0; +} + +int apk_trust_init(struct apk_trust *trust, int dirfd, struct apk_string_array *pkey_files) +{ + char **fn; + + *trust = (struct apk_trust){ + .mdctx = EVP_MD_CTX_new(), + }; + if (!trust->mdctx) return -ENOMEM; + EVP_MD_CTX_set_flags(trust->mdctx, EVP_MD_CTX_FLAG_FINALISE); + list_init(&trust->trusted_key_list); + list_init(&trust->private_key_list); + apk_dir_foreach_file(dirfd, __apk_trust_load_pubkey, trust); + + foreach_array_item(fn, pkey_files) { + struct apk_trust_key *key = apk_trust_load_key(AT_FDCWD, *fn); + if (IS_ERR(key)) return PTR_ERR(key); + list_add_tail(&key->key_node, &trust->private_key_list); + } + + return 0; +} + +static void __apk_trust_free_keys(struct list_head *h) +{ + struct apk_trust_key *tkey, *n; + + list_for_each_entry_safe(tkey, n, h, key_node) { + list_del(&tkey->key_node); + apk_pkey_free(&tkey->key); + free(tkey->filename); + free(tkey); + } +} + +void apk_trust_free(struct apk_trust *trust) +{ + if (!trust->mdctx) return; + __apk_trust_free_keys(&trust->trusted_key_list); + __apk_trust_free_keys(&trust->private_key_list); + EVP_MD_CTX_free(trust->mdctx); +} + +struct apk_pkey *apk_trust_key_by_name(struct apk_trust *trust, const char *filename) +{ + struct apk_trust_key *tkey; + + list_for_each_entry(tkey, &trust->trusted_key_list, key_node) + if (tkey->filename && strcmp(tkey->filename, filename) == 0) + return &tkey->key; + return NULL; +} + + +/* Command group for signing */ + +#include "apk_applet.h" + +#define SIGNING_OPTIONS(OPT) \ + OPT(OPT_SIGN_sign_key, APK_OPT_ARG "sign-key") + +APK_OPT_GROUP(options_signing, "Signing", SIGNING_OPTIONS); + +static int option_parse_signing(void *ctx, struct apk_ctx *ac, int optch, const char *optarg) +{ + switch (optch) { + case OPT_SIGN_sign_key: + *apk_string_array_add(&ac->private_keys) = (char*) optarg; + break; + default: + return -ENOTSUP; + } + return 0; +} + +const struct apk_option_group optgroup_signing = { + .desc = options_signing, + .parse = option_parse_signing, +};