From 9b77c053e8fd03348ed04ba09ceaaf7ba99ca6f6 Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Wed, 22 Jul 2009 19:56:13 +0300 Subject: pkg: cleanup the signing code smaller callback and less cases to check. also reintroduce the oneshot digest flag, hopefully correct this time. --- src/apk_io.h | 1 + src/gunzip.c | 11 +++- src/io.c | 1 + src/package.c | 173 ++++++++++++++++++++++++++-------------------------------- src/verify.c | 3 +- 5 files changed, 90 insertions(+), 99 deletions(-) (limited to 'src') diff --git a/src/apk_io.h b/src/apk_io.h index 2520665..b76385c 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -36,6 +36,7 @@ struct apk_istream { }; #define APK_BSTREAM_SINGLE_READ 0x0001 +#define APK_BSTREAM_EOF 0x0002 struct apk_bstream { unsigned int flags; diff --git a/src/gunzip.c b/src/gunzip.c index f00d148..e5144a0 100644 --- a/src/gunzip.c +++ b/src/gunzip.c @@ -82,10 +82,13 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size) switch (r) { case Z_STREAM_END: /* Digest the inflated bytes */ + if ((gis->bs->flags & APK_BSTREAM_EOF) && + gis->zs.avail_in == 0) + gis->err = 1; if (gis->cb != NULL) { - r = gis->cb(gis->cbctx, APK_MPART_BOUNDARY, - APK_BLOB_PTR_LEN(gis->cbprev, - (void *)gis->zs.next_in - gis->cbprev)); + r = gis->cb(gis->cbctx, + gis->err ? APK_MPART_END : APK_MPART_BOUNDARY, + APK_BLOB_PTR_LEN(gis->cbprev, (void *) gis->zs.next_in - gis->cbprev)); if (r > 0) r = -ECANCELED; if (r != 0) { @@ -94,6 +97,8 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size) } gis->cbprev = gis->zs.next_in; } + if (gis->err) + goto ret; inflateEnd(&gis->zs); if (inflateInit2(&gis->zs, 15+32) != Z_OK) return -ENOMEM; diff --git a/src/io.c b/src/io.c index bb9acc8..da0e66f 100644 --- a/src/io.c +++ b/src/io.c @@ -260,6 +260,7 @@ static apk_blob_t mmap_read(void *stream, apk_blob_t token) ret = mbs->left; mbs->left = APK_BLOB_NULL; + mbs->bs.flags |= APK_BSTREAM_EOF; return ret; } diff --git a/src/package.c b/src/package.c index 5e4a3d2..4f6262e 100644 --- a/src/package.c +++ b/src/package.c @@ -426,108 +426,91 @@ int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data) { struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx; unsigned char calculated[EVP_MAX_MD_SIZE]; - int r; + int r, end_of_control; + + if ((part == APK_MPART_DATA) || + (part == APK_MPART_BOUNDARY && sctx->data_started)) + goto update_digest; + + /* Still in signature blocks? */ + if (!sctx->control_started) + goto reset_digest; + + /* Grab state and mark all remaining block as data */ + end_of_control = (sctx->data_started == 0); + sctx->data_started = 1; + + /* End of control-block and control does not have data checksum? */ + if (sctx->has_data_checksum == 0 && end_of_control) + goto update_digest; + + /* Drool in the remaining of the digest block now, we will finish + * it on all cases */ + EVP_DigestUpdate(&sctx->mdctx, data.ptr, data.len); + + /* End of control-block and checking control hash/signature or + * end of data-block and checking its hash/signature */ + if (sctx->has_data_checksum && !end_of_control) { + /* End of control-block and check it's hash */ + 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) + return -EKEYREJECTED; + sctx->data_verified = 1; + if (!(apk_flags & APK_ALLOW_UNTRUSTED) && + !sctx->control_verified) + return -ENOKEY; + return 0; + } - switch (part) { - case APK_MPART_DATA: - EVP_DigestUpdate(&sctx->mdctx, data.ptr, data.len); - break; - case APK_MPART_BOUNDARY: - EVP_DigestUpdate(&sctx->mdctx, data.ptr, data.len); - - /* We are not interested about checksums of signature, - * reset checksum if we are still in signatures */ - if (!sctx->control_started) { - EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL); - EVP_DigestInit_ex(&sctx->mdctx, sctx->md, NULL); - return 0; + switch (sctx->action) { + case APK_SIGN_VERIFY: + if (sctx->signature.pkey == NULL) { + if (apk_flags & APK_ALLOW_UNTRUSTED) + break; + return -ENOKEY; } - /* Are we in control part?. */ - if ((!sctx->control_started) || sctx->data_started) - return 0; - - /* 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) { - if (sctx->signature.pkey == NULL) { - if (!(apk_flags & APK_ALLOW_UNTRUSTED)) - return -ENOKEY; - } else { - r = EVP_VerifyFinal(&sctx->mdctx, - (unsigned char *) sctx->signature.data.ptr, - sctx->signature.data.len, - sctx->signature.pkey); - if (r != 1) - return -EKEYREJECTED; - - sctx->control_verified = 1; - } - EVP_DigestInit_ex(&sctx->mdctx, sctx->md, NULL); - return 0; - } 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); - return -ECANCELED; - } else { - /* Reset digest for hashing data */ - EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL); - EVP_DigestInit_ex(&sctx->mdctx, sctx->md, NULL); - - if (sctx->action == APK_SIGN_VERIFY_IDENTITY) { - if (memcmp(calculated, sctx->identity.data, - sctx->identity.type) != 0) - return -EKEYREJECTED; - sctx->control_verified = 1; - } - } - break; - case APK_MPART_END: - 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) - return -EKEYREJECTED; - sctx->data_verified = 1; - if (!(apk_flags & APK_ALLOW_UNTRUSTED) && - !sctx->control_verified) - return -ENOKEY; - } else if (sctx->action == APK_SIGN_VERIFY) { - if (sctx->signature.pkey == NULL) - return -EKEYREJECTED; - - /* 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) - return -EKEYREJECTED; - - sctx->control_verified = 1; + r = EVP_VerifyFinal(&sctx->mdctx, + (unsigned char *) sctx->signature.data.ptr, + sctx->signature.data.len, + sctx->signature.pkey); + if (r != 1) + return -EKEYREJECTED; + sctx->control_verified = 1; + if (!sctx->has_data_checksum && part == APK_MPART_END) 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 -EKEYREJECTED; - sctx->control_verified = 1; + break; + case APK_SIGN_VERIFY_IDENTITY: + /* Reset digest for hashing data */ + EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL); + if (memcmp(calculated, sctx->identity.data, + sctx->identity.type) != 0) + return -EKEYREJECTED; + sctx->control_verified = 1; + if (!sctx->has_data_checksum && part == APK_MPART_END) 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); - } + break; + case APK_SIGN_GENERATE: + case APK_SIGN_GENERATE_V1: + /* Package identity is the checksum */ + sctx->identity.type = EVP_MD_CTX_size(&sctx->mdctx); + EVP_DigestFinal_ex(&sctx->mdctx, sctx->identity.data, NULL); + if (sctx->action == APK_SIGN_GENERATE && + sctx->has_data_checksum) + return -ECANCELED; break; } + +reset_digest: + EVP_DigestInit_ex(&sctx->mdctx, sctx->md, NULL); + EVP_MD_CTX_set_flags(&sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT); + return 0; + +update_digest: + EVP_MD_CTX_clear_flags(&sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT); + EVP_DigestUpdate(&sctx->mdctx, data.ptr, data.len); return 0; } diff --git a/src/verify.c b/src/verify.c index 1edf4e7..05ded17 100644 --- a/src/verify.c +++ b/src/verify.c @@ -20,6 +20,7 @@ static int verify_main(void *ctx, int argc, char **argv) struct apk_istream *is; int i, r, ok, rc = 0; + apk_flags |= APK_ALLOW_UNTRUSTED; for (i = 0; i < argc; i++) { apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL); is = apk_bstream_gunzip_mpart(apk_bstream_from_file(argv[i]), @@ -28,7 +29,7 @@ static int verify_main(void *ctx, int argc, char **argv) is->close(is); ok = sctx.control_verified && sctx.data_verified; if (apk_verbosity >= 1) - apk_message("%s: %s", argv[i], + apk_message("%s: %d - %s", argv[i], r, ok ? "OK" : sctx.data_verified ? "UNTRUSTED" : "FAILED"); if (!ok) -- cgit v1.2.3-70-g09d2