diff --git a/src/archive.c b/src/archive.c index b069f2d..7c26502 100644 --- a/src/archive.c +++ b/src/archive.c @@ -129,10 +129,8 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser, while ((r = is->read(is, &buf, 512)) == 512) { offset += 512; if (buf.name[0] == '\0') { - if (end) { - r = 0; - //break; - } + if (end) + break; end++; continue; } @@ -218,11 +216,18 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser, } EVP_MD_CTX_cleanup(&teis.mdctx); - if (r != 0) { - apk_error("Bad TAR header (r=%d)", r); - return -1; + /* Read remaining end-of-archive records, to ensure we read all of + * the file. The underlying istream is likely doing checksumming. */ + if (r == 512) { + while ((r = is->read(is, &buf, 512)) == 512) + if (buf.name[0] != 0) + return -1; } + /* Check that there was no partial record */ + if (r != 0) + return -1; + return 0; err: diff --git a/src/database.c b/src/database.c index 40c6bf3..65f8633 100644 --- a/src/database.c +++ b/src/database.c @@ -39,6 +39,7 @@ struct install_ctx { int script; struct apk_db_dir_instance *diri; struct apk_checksum data_csum; + struct apk_sign_ctx sctx; apk_progress_cb cb; void *cb_ctx; @@ -1247,6 +1248,9 @@ static int apk_db_install_archive_entry(void *_ctx, const char *p; int r = 0, type = APK_SCRIPT_INVALID; + if (apk_sign_ctx_process_file(&ctx->sctx, ae, is) == 0) + return 0; + /* Package metainfo and script processing */ if (ae->name[0] == '.') { /* APK 2.0 format */ @@ -1329,12 +1333,12 @@ static int apk_db_install_archive_entry(void *_ctx, if (opkg->name != pkg->name) { if (!(apk_flags & APK_FORCE)) { apk_error("%s: Trying to overwrite %s " - "owned by %s.\n", + "owned by %s.", pkg->name->name, ae->name, opkg->name->name); return -1; } - apk_warning("%s: Overwriting %s owned by %s.\n", + apk_warning("%s: Overwriting %s owned by %s.", pkg->name->name, ae->name, opkg->name->name); } @@ -1430,9 +1434,8 @@ static int apk_db_unpack_pkg(struct apk_database *db, struct install_ctx ctx; struct apk_bstream *bs = NULL; struct apk_istream *tar; - struct apk_sign_ctx sctx; char pkgname[256], file[256]; - int i, need_copy = FALSE; + int r, i, need_copy = FALSE; snprintf(pkgname, sizeof(pkgname), "%s-%s.apk", newpkg->name->name, newpkg->version); @@ -1487,17 +1490,17 @@ static int apk_db_unpack_pkg(struct apk_database *db, .cb = cb, .cb_ctx = cb_ctx, }; - 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) - goto err_close; + apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &newpkg->csum); + tar = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx); + r = apk_tar_parse(tar, apk_db_install_archive_entry, &ctx); + apk_sign_ctx_free(&ctx.sctx); tar->close(tar); - /* Check the package checksum */ - if (apk_checksum_compare(&ctx.data_csum, &newpkg->csum) != 0) - apk_warning("%s-%s: checksum does not match", - newpkg->name->name, newpkg->version); + if (r != 0) { + apk_error("%s-%s: package integrity check failed", + newpkg->name->name, newpkg->version); + return -1; + } if (need_copy) { char file2[256]; @@ -1507,9 +1510,6 @@ static int apk_db_unpack_pkg(struct apk_database *db, } return 0; -err_close: - bs->close(bs, NULL); - return -1; } int apk_db_install_pkg(struct apk_database *db, diff --git a/src/gunzip.c b/src/gunzip.c index 2b30d46..3f9a253 100644 --- a/src/gunzip.c +++ b/src/gunzip.c @@ -62,9 +62,16 @@ static size_t gzi_read(void *stream, void *ptr, size_t size) gis->z_err = Z_DATA_ERROR; return size - gis->zs.avail_out; } else if (gis->zs.avail_in == 0) { - if (gis->cb != NULL) - gis->cb(gis->cbctx, APK_MPART_END, - APK_BLOB_NULL); + if (gis->cb != NULL) { + r = gis->cb(gis->cbctx, APK_MPART_END, + APK_BLOB_NULL); + if (r != 0) { + gis->z_err = Z_STREAM_END; + if (r > 0) + r = -1; + return r; + } + } gis->z_err = Z_STREAM_END; return size - gis->zs.avail_out; } diff --git a/src/package.c b/src/package.c index 28f7f6e..78f7cb6 100644 --- a/src/package.c +++ b/src/package.c @@ -275,7 +275,6 @@ void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action, ctx->md = EVP_md5(); ctx->control_started = 1; ctx->data_started = 1; - ctx->has_data_checksum = 1; } else { ctx->md = EVP_sha1(); } @@ -438,7 +437,7 @@ int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data) sctx->signature.data.len, sctx->signature.pkey); if (r != 1) - return 1; + return -1; sctx->control_verified = 1; EVP_DigestInit_ex(&sctx->mdctx, sctx->md, NULL); @@ -457,9 +456,9 @@ int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data) if (sctx->action == APK_SIGN_VERIFY_IDENTITY) { if (memcmp(calculated, sctx->identity.data, - sctx->identity.type) == 0) - sctx->control_verified = 1; - return 1; + sctx->identity.type) != 0) + return -1; + sctx->control_verified = 1; } } break; @@ -467,29 +466,39 @@ int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data) 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 && + if (EVP_MD_CTX_size(&sctx->mdctx) == 0 || memcmp(calculated, sctx->data_checksum, - EVP_MD_CTX_size(&sctx->mdctx)) == 0) - sctx->data_verified = 1; + EVP_MD_CTX_size(&sctx->mdctx)) != 0) + return -1; + sctx->data_verified = 1; } else if (sctx->action == APK_SIGN_VERIFY) { if (sctx->signature.pkey == NULL) - return 1; + 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; - } + if (r != 1) + return -1; + + sctx->control_verified = 1; + sctx->data_verified = 1; + } else if (sctx->action == APK_SIGN_VERIFY_IDENTITY) { + EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL); + if (EVP_MD_CTX_size(&sctx->mdctx) == 0 || + memcmp(calculated, sctx->identity.data, + EVP_MD_CTX_size(&sctx->mdctx)) != 0) + return -1; + sctx->control_verified = 1; + sctx->data_verified = 1; } 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); } - return 1; + break; } return 0; }