aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-07-20 11:13:03 +0300
committerTimo Teras <timo.teras@iki.fi>2009-07-20 11:13:03 +0300
commiteca9c22205105eba20e1e28ddae8ad9da81c5323 (patch)
tree3a31082b2a5082c10047249a0348478f77c93cf7
parent99be653f141f57e1474bd645efd770aa3e3bd68f (diff)
downloadaports-eca9c22205105eba20e1e28ddae8ad9da81c5323.tar.bz2
aports-eca9c22205105eba20e1e28ddae8ad9da81c5323.tar.xz
db: signed index loading (ref #46)
prefer index in the new format as signed .tar.gz.
-rw-r--r--src/add.c2
-rw-r--r--src/apk_database.h3
-rw-r--r--src/apk_package.h13
-rw-r--r--src/archive.c5
-rw-r--r--src/cache.c5
-rw-r--r--src/database.c116
-rw-r--r--src/index.c2
-rw-r--r--src/package.c110
-rw-r--r--src/verify.c13
9 files changed, 217 insertions, 52 deletions
diff --git a/src/add.c b/src/add.c
index c05d257705..fac1edc060 100644
--- a/src/add.c
+++ b/src/add.c
@@ -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) {
diff --git a/src/apk_database.h b/src/apk_database.h
index 979d0e862b..4cf8b14b96 100644
--- a/src/apk_database.h
+++ b/src/apk_database.h
@@ -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);
diff --git a/src/apk_package.h b/src/apk_package.h
index f77637a6a6..c8166338b5 100644
--- a/src/apk_package.h
+++ b/src/apk_package.h
@@ -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,
diff --git a/src/archive.c b/src/archive.c
index 717c67c1cb..b069f2d8c7 100644
--- a/src/archive.c
+++ b/src/archive.c
@@ -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;
diff --git a/src/cache.c b/src/cache.c
index 7bcd636e74..7b5b7f1a59 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -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,
diff --git a/src/database.c b/src/database.c
index db8f521d7d..331357a9e6 100644
--- a/src/database.c
+++ b/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)
diff --git a/src/index.c b/src/index.c
index c3124d881f..2a7365e57b 100644
--- a/src/index.c
+++ b/src/index.c
@@ -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);
diff --git a/src/package.c b/src/package.c
index df4922b6e8..28f7f6e57d 100644
--- a/src/package.c
+++ b/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);
diff --git a/src/verify.c b/src/verify.c
index 2fed4bd926..1edf4e719b 100644
--- a/src/verify.c
+++ b/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;
}