Commit e30834fd authored by Timo Teräs's avatar Timo Teräs

digest: use oneshot context flag where approriate

speeds up digest calculation on some cases.
parent 09428323
......@@ -35,7 +35,10 @@ struct apk_istream {
void (*close)(void *stream);
};
#define APK_BSTREAM_SINGLE_READ 0x0001
struct apk_bstream {
unsigned int flags;
apk_blob_t (*read)(void *stream, apk_blob_t token);
void (*close)(void *stream, size_t *size);
};
......@@ -45,11 +48,11 @@ struct apk_ostream {
void (*close)(void *stream);
};
#define APK_MPART_BEGIN 0
#define APK_MPART_BOUNDARY 1
#define APK_MPART_END 2
#define APK_MPART_DATA 1 /* data processed so far */
#define APK_MPART_BOUNDARY 2 /* final part of data, before boundary */
#define APK_MPART_END 3 /* signals end of stream */
typedef int (*apk_multipart_cb)(void *ctx, EVP_MD_CTX *mdctx, int part);
typedef int (*apk_multipart_cb)(void *ctx, int part, apk_blob_t data);
struct apk_istream *apk_bstream_gunzip_mpart(struct apk_bstream *,
apk_multipart_cb cb, void *ctx);
......
......@@ -45,6 +45,7 @@ struct apk_sign_ctx {
int data_verified : 1;
char data_checksum[EVP_MAX_MD_SIZE];
struct apk_checksum identity;
EVP_MD_CTX mdctx;
struct {
apk_blob_t data;
......@@ -97,7 +98,7 @@ 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_mpart_cb(void *ctx, EVP_MD_CTX *mdctx, int part);
int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t blob);
int apk_deps_add(struct apk_dependency_array **depends,
struct apk_dependency *dep);
......
......@@ -1332,22 +1332,6 @@ static void apk_db_purge_pkg(struct apk_database *db,
apk_pkg_set_state(db, pkg, APK_PKG_NOT_INSTALLED);
}
static int apk_db_gzip_part(void *pctx, EVP_MD_CTX *mdctx, int part)
{
struct install_ctx *ctx = (struct install_ctx *) pctx;
switch (part) {
case APK_MPART_BEGIN:
EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
break;
case APK_MPART_END:
ctx->data_csum.type = EVP_MD_CTX_size(mdctx);
EVP_DigestFinal_ex(mdctx, ctx->data_csum.data, NULL);
break;
}
return 0;
}
static int apk_db_unpack_pkg(struct apk_database *db,
struct apk_package *newpkg,
int upgrade, apk_progress_cb cb, void *cb_ctx)
......@@ -1355,6 +1339,7 @@ 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;
......@@ -1411,8 +1396,9 @@ static int apk_db_unpack_pkg(struct apk_database *db,
.cb = cb,
.cb_ctx = cb_ctx,
};
tar = apk_bstream_gunzip_mpart(bs, apk_db_gzip_part, &ctx);
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY);
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;
tar->close(tar);
......
......@@ -23,17 +23,16 @@ struct apk_gzip_istream {
z_stream zs;
int z_err;
EVP_MD_CTX mdctx;
void *mdblock;
apk_multipart_cb cb;
void *cbctx;
void *cbprev;
};
static size_t gzi_read(void *stream, void *ptr, size_t size)
{
struct apk_gzip_istream *gis =
container_of(stream, struct apk_gzip_istream, is);
int r;
if (gis->z_err == Z_DATA_ERROR || gis->z_err == Z_ERRNO)
return -1;
......@@ -50,22 +49,22 @@ static size_t gzi_read(void *stream, void *ptr, size_t size)
if (gis->zs.avail_in == 0) {
apk_blob_t blob;
if (gis->cb != NULL && gis->mdblock != NULL) {
/* Digest the inflated bytes */
EVP_DigestUpdate(&gis->mdctx, gis->mdblock,
(void *)gis->zs.next_in - gis->mdblock);
if (gis->cb != NULL && gis->cbprev != NULL) {
gis->cb(gis->cbctx, APK_MPART_DATA,
APK_BLOB_PTR_LEN(gis->cbprev,
(void *)gis->zs.next_in - gis->cbprev));
}
blob = gis->bs->read(gis->bs, APK_BLOB_NULL);
gis->mdblock = blob.ptr;
gis->cbprev = blob.ptr;
gis->zs.avail_in = blob.len;
gis->zs.next_in = (void *) gis->mdblock;
gis->zs.next_in = (void *) gis->cbprev;
if (gis->zs.avail_in < 0) {
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, &gis->mdctx,
APK_MPART_END);
gis->cb(gis->cbctx, APK_MPART_END,
APK_BLOB_NULL);
gis->z_err = Z_STREAM_END;
return size - gis->zs.avail_out;
}
......@@ -75,14 +74,16 @@ static size_t gzi_read(void *stream, void *ptr, size_t size)
if (gis->z_err == Z_STREAM_END) {
/* Digest the inflated bytes */
if (gis->cb != NULL) {
EVP_DigestUpdate(&gis->mdctx, gis->mdblock,
(void *)gis->zs.next_in - gis->mdblock);
gis->mdblock = gis->zs.next_in;
if (gis->cb(gis->cbctx, &gis->mdctx,
APK_MPART_BOUNDARY)) {
gis->z_err = Z_STREAM_END;
break;
r = gis->cb(gis->cbctx, APK_MPART_BOUNDARY,
APK_BLOB_PTR_LEN(gis->cbprev,
(void *)gis->zs.next_in - gis->cbprev));
if (r != 0) {
gis->z_err = Z_DATA_ERROR;
if (r > 0)
r = -1;
return r;
}
gis->cbprev = gis->zs.next_in;
}
inflateEnd(&gis->zs);
if (inflateInit2(&gis->zs, 15+32) != Z_OK)
......@@ -102,8 +103,6 @@ static void gzi_close(void *stream)
struct apk_gzip_istream *gis =
container_of(stream, struct apk_gzip_istream, is);
if (gis->cb != NULL)
EVP_MD_CTX_cleanup(&gis->mdctx);
inflateEnd(&gis->zs);
gis->bs->close(gis->bs, NULL);
free(gis);
......@@ -135,11 +134,6 @@ struct apk_istream *apk_bstream_gunzip_mpart(struct apk_bstream *bs,
goto err;
}
if (gis->cb != NULL) {
EVP_MD_CTX_init(&gis->mdctx);
cb(ctx, &gis->mdctx, APK_MPART_BEGIN);
}
return &gis->is;
err:
bs->close(bs, NULL);
......
......@@ -295,6 +295,7 @@ static struct apk_bstream *apk_mmap_bstream_from_fd(int fd)
}
mbs->bs = (struct apk_bstream) {
.flags = APK_BSTREAM_SINGLE_READ,
.read = mmap_read,
.close = mmap_close,
};
......@@ -466,6 +467,8 @@ int apk_file_get_info(const char *filename, int checksum, struct apk_file_info *
apk_blob_t blob;
EVP_DigestInit(&mdctx, apk_get_digest(checksum));
if (bs->flags & APK_BSTREAM_SINGLE_READ)
EVP_MD_CTX_set_flags(&mdctx, EVP_MD_CTX_FLAG_ONESHOT);
while (!APK_BLOB_IS_NULL(blob = bs->read(bs, APK_BLOB_NULL)))
EVP_DigestUpdate(&mdctx, (void*) blob.ptr, blob.len);
fi->csum.type = EVP_MD_CTX_size(&mdctx);
......
......@@ -275,6 +275,9 @@ void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action)
ctx->md = EVP_sha1();
break;
}
EVP_MD_CTX_init(&ctx->mdctx);
EVP_DigestInit_ex(&ctx->mdctx, ctx->md, NULL);
EVP_MD_CTX_set_flags(&ctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
}
......@@ -338,22 +341,26 @@ int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx,
return 0;
}
int apk_sign_ctx_mpart_cb(void *ctx, EVP_MD_CTX *mdctx, int part)
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;
switch (part) {
case APK_MPART_BEGIN:
EVP_DigestInit_ex(mdctx, sctx->md, NULL);
case APK_MPART_DATA:
EVP_MD_CTX_clear_flags(&sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
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(mdctx, calculated, NULL);
EVP_DigestInit_ex(mdctx, sctx->md, NULL);
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);
return 0;
}
......@@ -367,7 +374,7 @@ int apk_sign_ctx_mpart_cb(void *ctx, EVP_MD_CTX *mdctx, int part)
/* Verify the signature if we have public key */
if (sctx->action == APK_SIGN_VERIFY &&
sctx->signature.pkey != NULL) {
r = EVP_VerifyFinal(mdctx,
r = EVP_VerifyFinal(&sctx->mdctx,
(unsigned char *) sctx->signature.data.ptr,
sctx->signature.data.len,
sctx->signature.pkey);
......@@ -375,32 +382,34 @@ int apk_sign_ctx_mpart_cb(void *ctx, EVP_MD_CTX *mdctx, int part)
return 1;
sctx->control_verified = 1;
EVP_DigestInit_ex(mdctx, sctx->md, NULL);
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) {
/* Package identity is checksum of control block */
sctx->identity.type = EVP_MD_CTX_size(mdctx);
EVP_DigestFinal_ex(mdctx, sctx->identity.data, NULL);
sctx->identity.type = EVP_MD_CTX_size(&sctx->mdctx);
EVP_DigestFinal_ex(&sctx->mdctx, sctx->identity.data, NULL);
return 1;
} else {
/* Reset digest for hashing data */
EVP_DigestFinal_ex(mdctx, calculated, NULL);
EVP_DigestInit_ex(mdctx, sctx->md, NULL);
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);
}
break;
case APK_MPART_END:
if (sctx->action == APK_SIGN_VERIFY) {
if (sctx->has_data_checksum) {
/* Check that data checksum matches */
EVP_DigestFinal_ex(mdctx, calculated, NULL);
if (EVP_MD_CTX_size(mdctx) != 0 &&
EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL);
if (EVP_MD_CTX_size(&sctx->mdctx) != 0 &&
memcmp(calculated, sctx->data_checksum,
EVP_MD_CTX_size(mdctx)) == 0)
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(mdctx,
r = EVP_VerifyFinal(&sctx->mdctx,
(unsigned char *) sctx->signature.data.ptr,
sctx->signature.data.len,
sctx->signature.pkey);
......@@ -411,8 +420,8 @@ int apk_sign_ctx_mpart_cb(void *ctx, EVP_MD_CTX *mdctx, int part)
}
} else if (!sctx->has_data_checksum) {
/* Package identity is checksum of all data */
sctx->identity.type = EVP_MD_CTX_size(mdctx);
EVP_DigestFinal_ex(mdctx, sctx->identity.data, NULL);
sctx->identity.type = EVP_MD_CTX_size(&sctx->mdctx);
EVP_DigestFinal_ex(&sctx->mdctx, sctx->identity.data, NULL);
}
return 1;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment