db: signed index loading (ref #46)
prefer index in the new format as signed .tar.gz.cute-signatures
parent
99be653f14
commit
eca9c22205
|
@ -119,7 +119,7 @@ static int add_main(void *ctx, int argc, char **argv)
|
|||
struct apk_package *pkg;
|
||||
struct apk_sign_ctx sctx;
|
||||
|
||||
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY);
|
||||
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL);
|
||||
pkg = apk_pkg_read(&db, argv[i], &sctx);
|
||||
apk_sign_ctx_free(&sctx);
|
||||
if (pkg == NULL) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define APK_CACHE_CSUM_BYTES 4
|
||||
|
||||
extern const char * const apk_index_gz;
|
||||
extern const char * const apkindex_tar_gz;
|
||||
|
||||
struct apk_name;
|
||||
APK_ARRAY(apk_name_array, struct apk_name *);
|
||||
|
@ -144,7 +145,7 @@ int apk_db_index_write(struct apk_database *db, struct apk_ostream *os);
|
|||
int apk_db_add_repository(apk_database_t db, apk_blob_t repository);
|
||||
int apk_repository_update(struct apk_database *db, struct apk_repository *repo);
|
||||
int apk_cache_download(struct apk_database *db, struct apk_checksum *csum,
|
||||
const char *url, const char *item);
|
||||
const char *url, const char *item, int verify);
|
||||
int apk_cache_exists(struct apk_database *db, struct apk_checksum *csum,
|
||||
const char *item);
|
||||
|
||||
|
|
|
@ -30,9 +30,11 @@ struct apk_name;
|
|||
#define APK_PKG_NOT_INSTALLED 0
|
||||
#define APK_PKG_INSTALLED 1
|
||||
|
||||
#define APK_SIGN_VERIFY 0
|
||||
#define APK_SIGN_GENERATE_V1 1
|
||||
#define APK_SIGN_GENERATE 2
|
||||
#define APK_SIGN_NONE 0
|
||||
#define APK_SIGN_VERIFY 1
|
||||
#define APK_SIGN_VERIFY_IDENTITY 2
|
||||
#define APK_SIGN_GENERATE_V1 3
|
||||
#define APK_SIGN_GENERATE 4
|
||||
|
||||
struct apk_sign_ctx {
|
||||
int action;
|
||||
|
@ -93,11 +95,14 @@ 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);
|
||||
void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action,
|
||||
struct apk_checksum *identity);
|
||||
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,
|
||||
struct apk_istream *is);
|
||||
int apk_sign_ctx_verify_tar(void *ctx, const struct apk_file_info *fi,
|
||||
struct apk_istream *is);
|
||||
int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t blob);
|
||||
|
||||
int apk_deps_add(struct apk_dependency_array **depends,
|
||||
|
|
|
@ -104,12 +104,17 @@ static size_t tar_entry_read(void *stream, void *ptr, size_t size)
|
|||
return size;
|
||||
}
|
||||
|
||||
static void tar_entry_close(void *stream)
|
||||
{
|
||||
}
|
||||
|
||||
int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
|
||||
void *ctx)
|
||||
{
|
||||
struct apk_file_info entry;
|
||||
struct apk_tar_entry_istream teis = {
|
||||
.is.read = tar_entry_read,
|
||||
.is.close = tar_entry_close,
|
||||
.tar_is = is,
|
||||
};
|
||||
struct tar_header buf;
|
||||
|
|
|
@ -54,7 +54,7 @@ static int cache_download(struct apk_database *db)
|
|||
continue;
|
||||
|
||||
r = apk_cache_download(db, &pkg->csum, db->repos[i].url,
|
||||
pkgfile);
|
||||
pkgfile, APK_SIGN_VERIFY_IDENTITY);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -91,7 +91,8 @@ static int cache_clean(struct apk_database *db)
|
|||
apk_blob_pull_hexdump(&b, APK_BLOB_BUF(csum));
|
||||
apk_blob_pull_char(&b, '.');
|
||||
|
||||
if (apk_blob_compare(b, APK_BLOB_STR(apk_index_gz)) == 0) {
|
||||
if (apk_blob_compare(b, APK_BLOB_STR(apk_index_gz)) == 0 ||
|
||||
apk_blob_compare(b, APK_BLOB_STR(apkindex_tar_gz)) == 0) {
|
||||
/* Index - check for matching repository */
|
||||
for (i = 0; i < db->num_repos; i++) {
|
||||
if (memcmp(db->repos[i].csum.data,
|
||||
|
|
116
src/database.c
116
src/database.c
|
@ -25,7 +25,9 @@
|
|||
#include "apk_database.h"
|
||||
#include "apk_state.h"
|
||||
#include "apk_applet.h"
|
||||
#include "apk_archive.h"
|
||||
|
||||
const char * const apkindex_tar_gz = "APKINDEX.tar.gz";
|
||||
const char * const apk_index_gz = "APK_INDEX.gz";
|
||||
static const char * const apk_static_cache_dir = "var/lib/apk";
|
||||
static const char * const apk_linked_cache_dir = "etc/apk/cache";
|
||||
|
@ -1034,12 +1036,13 @@ static struct apk_bstream *apk_repository_file_open(struct apk_repository *repo,
|
|||
}
|
||||
|
||||
int apk_cache_download(struct apk_database *db, struct apk_checksum *csum,
|
||||
const char *url, const char *item)
|
||||
const char *url, const char *item, int verify)
|
||||
{
|
||||
char tmp[256], tmp2[256];
|
||||
int r;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%s/%s", url, item);
|
||||
snprintf(tmp, sizeof(tmp), "%s%s%s",
|
||||
url, url[strlen(url)-1] == '/' ? "" : "/", item);
|
||||
apk_message("fetch %s", tmp);
|
||||
|
||||
if (apk_flags & APK_SIMULATE)
|
||||
|
@ -1050,6 +1053,24 @@ int apk_cache_download(struct apk_database *db, struct apk_checksum *csum,
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (verify != APK_SIGN_NONE) {
|
||||
struct apk_istream *is;
|
||||
struct apk_sign_ctx sctx;
|
||||
int ok;
|
||||
|
||||
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL);
|
||||
is = apk_bstream_gunzip_mpart(apk_bstream_from_file(tmp2),
|
||||
apk_sign_ctx_mpart_cb, &sctx);
|
||||
is->close(is);
|
||||
r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx);
|
||||
ok = (r != 0) && sctx.control_verified && sctx.data_verified;
|
||||
apk_sign_ctx_free(&sctx);
|
||||
if (!ok) {
|
||||
unlink(tmp2);
|
||||
return -10;
|
||||
}
|
||||
}
|
||||
|
||||
apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE);
|
||||
if (rename(tmp2, tmp) < 0)
|
||||
return -errno;
|
||||
|
@ -1069,12 +1090,59 @@ int apk_cache_exists(struct apk_database *db, struct apk_checksum *csum,
|
|||
return access(tmp, R_OK | W_OK) == 0;
|
||||
}
|
||||
|
||||
static int apk_cache_delete(struct apk_database *db, struct apk_checksum *csum,
|
||||
const char *item)
|
||||
{
|
||||
char tmp[256];
|
||||
|
||||
if (db->root == NULL)
|
||||
return 0;
|
||||
|
||||
apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE);
|
||||
return unlink(tmp);
|
||||
}
|
||||
|
||||
int apk_repository_update(struct apk_database *db, struct apk_repository *repo)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (repo->csum.type == APK_CHECKSUM_NONE)
|
||||
return 0;
|
||||
|
||||
return apk_cache_download(db, &repo->csum, repo->url, apk_index_gz);
|
||||
r = apk_cache_download(db, &repo->csum, repo->url, apkindex_tar_gz,
|
||||
APK_SIGN_VERIFY);
|
||||
if (r == 0 || r == -10) {
|
||||
apk_cache_delete(db, &repo->csum, apk_index_gz);
|
||||
return r;
|
||||
}
|
||||
|
||||
return apk_cache_download(db, &repo->csum, repo->url, apk_index_gz,
|
||||
APK_SIGN_NONE);
|
||||
}
|
||||
|
||||
struct apkindex_ctx {
|
||||
struct apk_database *db;
|
||||
struct apk_sign_ctx sctx;
|
||||
int repo;
|
||||
};
|
||||
|
||||
static int load_apkindex(void *sctx, const struct apk_file_info *fi,
|
||||
struct apk_istream *is)
|
||||
{
|
||||
struct apkindex_ctx *ctx = (struct apkindex_ctx *) sctx;
|
||||
struct apk_bstream *bs;
|
||||
|
||||
if (apk_sign_ctx_process_file(&ctx->sctx, fi, is) == 0)
|
||||
return 0;
|
||||
|
||||
if (strcmp(fi->name, "APKINDEX") != 0)
|
||||
return 0;
|
||||
|
||||
bs = apk_bstream_from_istream(is);
|
||||
apk_db_index_read(ctx->db, bs, ctx->repo);
|
||||
bs->close(bs, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
|
||||
|
@ -1082,7 +1150,7 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
|
|||
struct apk_database *db = _db.db;
|
||||
struct apk_bstream *bs = NULL;
|
||||
struct apk_repository *repo;
|
||||
int r, n = 1;
|
||||
int r, targz = 1;
|
||||
|
||||
if (repository.ptr == NULL || *repository.ptr == '\0'
|
||||
|| *repository.ptr == '#')
|
||||
|
@ -1102,26 +1170,44 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
|
|||
apk_blob_checksum(repository, apk_default_checksum(), &repo->csum);
|
||||
|
||||
if (apk_flags & APK_UPDATE_CACHE)
|
||||
n = apk_repository_update(db, repo);
|
||||
apk_repository_update(db, repo);
|
||||
|
||||
bs = apk_db_cache_open(db, &repo->csum, apk_index_gz);
|
||||
bs = apk_db_cache_open(db, &repo->csum, apkindex_tar_gz);
|
||||
if (bs == NULL) {
|
||||
if (n == 1)
|
||||
n = apk_repository_update(db, repo);
|
||||
if (n < 0)
|
||||
return n;
|
||||
bs = apk_db_cache_open(db, &repo->csum, apk_index_gz);
|
||||
targz = 0;
|
||||
}
|
||||
} else {
|
||||
bs = apk_repository_file_open(repo, apk_index_gz);
|
||||
bs = apk_repository_file_open(repo, apkindex_tar_gz);
|
||||
if (bs == NULL) {
|
||||
bs = apk_repository_file_open(repo, apk_index_gz);
|
||||
targz = 0;
|
||||
}
|
||||
}
|
||||
bs = apk_bstream_from_istream(apk_bstream_gunzip(bs));
|
||||
if (bs == NULL) {
|
||||
apk_warning("Failed to open index for %s", repo->url);
|
||||
return -1;
|
||||
}
|
||||
apk_db_index_read(db, bs, r);
|
||||
bs->close(bs, NULL);
|
||||
if (targz) {
|
||||
struct apk_istream *is;
|
||||
struct apkindex_ctx ctx;
|
||||
|
||||
ctx.db = db;
|
||||
ctx.repo = r;
|
||||
apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL);
|
||||
is = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx);
|
||||
r = apk_tar_parse(is, load_apkindex, &ctx);
|
||||
is->close(is);
|
||||
apk_sign_ctx_free(&ctx.sctx);
|
||||
if (!ctx.sctx.data_verified) {
|
||||
apk_error("Bad repository signature: %s", repo->url);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
bs = apk_bstream_from_istream(apk_bstream_gunzip(bs));
|
||||
apk_db_index_read(db, bs, r);
|
||||
bs->close(bs, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1396,7 +1482,7 @@ static int apk_db_unpack_pkg(struct apk_database *db,
|
|||
.cb = cb,
|
||||
.cb_ctx = cb_ctx,
|
||||
};
|
||||
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY);
|
||||
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY_IDENTITY, &newpkg->csum);
|
||||
tar = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &sctx);
|
||||
apk_sign_ctx_free(&sctx);
|
||||
if (apk_tar_parse(tar, apk_db_install_archive_entry, &ctx) != 0)
|
||||
|
|
|
@ -159,7 +159,7 @@ static int index_main(void *ctx, int argc, char **argv)
|
|||
|
||||
if (!found) {
|
||||
struct apk_sign_ctx sctx;
|
||||
apk_sign_ctx_init(&sctx, ictx->method);
|
||||
apk_sign_ctx_init(&sctx, ictx->method, NULL);
|
||||
if (apk_pkg_read(&db, argv[i], &sctx) != NULL)
|
||||
newpkgs++;
|
||||
apk_sign_ctx_free(&sctx);
|
||||
|
|
110
src/package.c
110
src/package.c
|
@ -256,14 +256,31 @@ int apk_script_type(const char *name)
|
|||
return APK_SCRIPT_INVALID;
|
||||
}
|
||||
|
||||
void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action)
|
||||
void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action,
|
||||
struct apk_checksum *identity)
|
||||
{
|
||||
memset(ctx, 0, sizeof(struct apk_sign_ctx));
|
||||
ctx->action = action;
|
||||
switch (action) {
|
||||
case APK_SIGN_NONE:
|
||||
ctx->md = EVP_md_null();
|
||||
ctx->control_started = 1;
|
||||
ctx->data_started = 1;
|
||||
break;
|
||||
case APK_SIGN_VERIFY:
|
||||
ctx->md = EVP_md_null();
|
||||
break;
|
||||
case APK_SIGN_VERIFY_IDENTITY:
|
||||
if (identity->type == APK_CHECKSUM_MD5) {
|
||||
ctx->md = EVP_md5();
|
||||
ctx->control_started = 1;
|
||||
ctx->data_started = 1;
|
||||
ctx->has_data_checksum = 1;
|
||||
} else {
|
||||
ctx->md = EVP_sha1();
|
||||
}
|
||||
memcpy(&ctx->identity, identity, sizeof(ctx->identity));
|
||||
break;
|
||||
case APK_SIGN_GENERATE_V1:
|
||||
ctx->md = EVP_md5();
|
||||
ctx->control_started = 1;
|
||||
|
@ -341,6 +358,46 @@ int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int read_datahash(void *ctx, apk_blob_t line)
|
||||
{
|
||||
struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
|
||||
apk_blob_t l, r;
|
||||
|
||||
if (line.ptr == NULL || line.len < 1 || line.ptr[0] == '#')
|
||||
return 0;
|
||||
|
||||
if (!apk_blob_split(line, APK_BLOB_STR(" = "), &l, &r))
|
||||
return 0;
|
||||
|
||||
if (sctx->data_started == 0 &&
|
||||
apk_blob_compare(APK_BLOB_STR("datahash"), l) == 0) {
|
||||
sctx->has_data_checksum = 1;
|
||||
sctx->md = EVP_sha256();
|
||||
apk_blob_pull_hexdump(
|
||||
&r, APK_BLOB_PTR_LEN(sctx->data_checksum,
|
||||
EVP_MD_size(sctx->md)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int apk_sign_ctx_verify_tar(void *sctx, const struct apk_file_info *fi,
|
||||
struct apk_istream *is)
|
||||
{
|
||||
struct apk_sign_ctx *ctx = (struct apk_sign_ctx *) sctx;
|
||||
|
||||
if (apk_sign_ctx_process_file(ctx, fi, is) == 0)
|
||||
return 0;
|
||||
|
||||
if (strcmp(fi->name, ".PKGINFO") == 0) {
|
||||
apk_blob_t blob = apk_blob_from_istream(is, fi->size);
|
||||
apk_blob_for_each_segment(blob, "\n", read_datahash, ctx);
|
||||
free(blob.ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
|
||||
{
|
||||
struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
|
||||
|
@ -370,6 +427,8 @@ int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
|
|||
|
||||
/* End of control block, make sure rest is handled as data */
|
||||
sctx->data_started = 1;
|
||||
if (!sctx->has_data_checksum)
|
||||
return 0;
|
||||
|
||||
/* Verify the signature if we have public key */
|
||||
if (sctx->action == APK_SIGN_VERIFY &&
|
||||
|
@ -385,8 +444,7 @@ int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
|
|||
EVP_DigestInit_ex(&sctx->mdctx, sctx->md, NULL);
|
||||
EVP_MD_CTX_set_flags(&sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
|
||||
return 0;
|
||||
} else if (sctx->action == APK_SIGN_GENERATE &&
|
||||
sctx->has_data_checksum) {
|
||||
} else if (sctx->action == APK_SIGN_GENERATE) {
|
||||
/* Package identity is checksum of control block */
|
||||
sctx->identity.type = EVP_MD_CTX_size(&sctx->mdctx);
|
||||
EVP_DigestFinal_ex(&sctx->mdctx, sctx->identity.data, NULL);
|
||||
|
@ -396,29 +454,37 @@ int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
|
|||
EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL);
|
||||
EVP_DigestInit_ex(&sctx->mdctx, sctx->md, NULL);
|
||||
EVP_MD_CTX_set_flags(&sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
|
||||
|
||||
if (sctx->action == APK_SIGN_VERIFY_IDENTITY) {
|
||||
if (memcmp(calculated, sctx->identity.data,
|
||||
sctx->identity.type) == 0)
|
||||
sctx->control_verified = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case APK_MPART_END:
|
||||
if (sctx->action == APK_SIGN_VERIFY) {
|
||||
if (sctx->has_data_checksum) {
|
||||
/* Check that data checksum matches */
|
||||
EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL);
|
||||
if (EVP_MD_CTX_size(&sctx->mdctx) != 0 &&
|
||||
memcmp(calculated, sctx->data_checksum,
|
||||
EVP_MD_CTX_size(&sctx->mdctx)) == 0)
|
||||
sctx->data_verified = 1;
|
||||
} else if (sctx->signature.pkey != NULL) {
|
||||
/* Assume that the data is fully signed */
|
||||
r = EVP_VerifyFinal(&sctx->mdctx,
|
||||
(unsigned char *) sctx->signature.data.ptr,
|
||||
sctx->signature.data.len,
|
||||
sctx->signature.pkey);
|
||||
if (r == 1) {
|
||||
sctx->control_verified = 1;
|
||||
sctx->data_verified = 1;
|
||||
}
|
||||
if (sctx->has_data_checksum) {
|
||||
/* Check that data checksum matches */
|
||||
EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL);
|
||||
if (EVP_MD_CTX_size(&sctx->mdctx) != 0 &&
|
||||
memcmp(calculated, sctx->data_checksum,
|
||||
EVP_MD_CTX_size(&sctx->mdctx)) == 0)
|
||||
sctx->data_verified = 1;
|
||||
} else if (sctx->action == APK_SIGN_VERIFY) {
|
||||
if (sctx->signature.pkey == NULL)
|
||||
return 1;
|
||||
|
||||
/* Assume that the data is fully signed */
|
||||
r = EVP_VerifyFinal(&sctx->mdctx,
|
||||
(unsigned char *) sctx->signature.data.ptr,
|
||||
sctx->signature.data.len,
|
||||
sctx->signature.pkey);
|
||||
if (r == 1) {
|
||||
sctx->control_verified = 1;
|
||||
sctx->data_verified = 1;
|
||||
}
|
||||
} else if (!sctx->has_data_checksum) {
|
||||
} else {
|
||||
/* Package identity is checksum of all data */
|
||||
sctx->identity.type = EVP_MD_CTX_size(&sctx->mdctx);
|
||||
EVP_DigestFinal_ex(&sctx->mdctx, sctx->identity.data, NULL);
|
||||
|
|
13
src/verify.c
13
src/verify.c
|
@ -16,14 +16,16 @@
|
|||
|
||||
static int verify_main(void *ctx, int argc, char **argv)
|
||||
{
|
||||
struct apk_database db;
|
||||
struct apk_sign_ctx sctx;
|
||||
int i, ok, rc = 0;
|
||||
struct apk_istream *is;
|
||||
int i, r, ok, rc = 0;
|
||||
|
||||
apk_db_open(&db, NULL, APK_OPENF_NO_STATE);
|
||||
for (i = 0; i < argc; i++) {
|
||||
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY);
|
||||
apk_pkg_read(&db, argv[i], &sctx);
|
||||
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL);
|
||||
is = apk_bstream_gunzip_mpart(apk_bstream_from_file(argv[i]),
|
||||
apk_sign_ctx_mpart_cb, &sctx);
|
||||
r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx);
|
||||
is->close(is);
|
||||
ok = sctx.control_verified && sctx.data_verified;
|
||||
if (apk_verbosity >= 1)
|
||||
apk_message("%s: %s", argv[i],
|
||||
|
@ -33,7 +35,6 @@ static int verify_main(void *ctx, int argc, char **argv)
|
|||
rc++;
|
||||
apk_sign_ctx_free(&sctx);
|
||||
}
|
||||
apk_db_close(&db);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue