From 84e3786e05bb8cda52548b8d98efe87f2a1b64ac Mon Sep 17 00:00:00 2001
From: Timo Teras <timo.teras@iki.fi>
Date: Tue, 21 Jul 2009 13:49:35 +0300
Subject: [PATCH] db: fixes to package checksumming while installing it

---
 src/archive.c  | 19 ++++++++++++-------
 src/database.c | 32 ++++++++++++++++----------------
 src/gunzip.c   | 13 ++++++++++---
 src/package.c  | 37 +++++++++++++++++++++++--------------
 4 files changed, 61 insertions(+), 40 deletions(-)

diff --git a/src/archive.c b/src/archive.c
index b069f2d8..7c265028 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 40c6bf39..65f86336 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 2b30d469..3f9a2535 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 28f7f6e5..78f7cb60 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;
 }
-- 
GitLab