pkg: cleanup the signing code

smaller callback and less cases to check. also reintroduce the
oneshot digest flag, hopefully correct this time.
cute-signatures
Timo Teras 2009-07-22 19:56:13 +03:00
parent 9b63730d84
commit 9b77c053e8
5 changed files with 90 additions and 99 deletions

View File

@ -36,6 +36,7 @@ struct apk_istream {
}; };
#define APK_BSTREAM_SINGLE_READ 0x0001 #define APK_BSTREAM_SINGLE_READ 0x0001
#define APK_BSTREAM_EOF 0x0002
struct apk_bstream { struct apk_bstream {
unsigned int flags; unsigned int flags;

View File

@ -82,10 +82,13 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size)
switch (r) { switch (r) {
case Z_STREAM_END: case Z_STREAM_END:
/* Digest the inflated bytes */ /* Digest the inflated bytes */
if ((gis->bs->flags & APK_BSTREAM_EOF) &&
gis->zs.avail_in == 0)
gis->err = 1;
if (gis->cb != NULL) { if (gis->cb != NULL) {
r = gis->cb(gis->cbctx, APK_MPART_BOUNDARY, r = gis->cb(gis->cbctx,
APK_BLOB_PTR_LEN(gis->cbprev, gis->err ? APK_MPART_END : APK_MPART_BOUNDARY,
(void *)gis->zs.next_in - gis->cbprev)); APK_BLOB_PTR_LEN(gis->cbprev, (void *) gis->zs.next_in - gis->cbprev));
if (r > 0) if (r > 0)
r = -ECANCELED; r = -ECANCELED;
if (r != 0) { 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; gis->cbprev = gis->zs.next_in;
} }
if (gis->err)
goto ret;
inflateEnd(&gis->zs); inflateEnd(&gis->zs);
if (inflateInit2(&gis->zs, 15+32) != Z_OK) if (inflateInit2(&gis->zs, 15+32) != Z_OK)
return -ENOMEM; return -ENOMEM;

View File

@ -260,6 +260,7 @@ static apk_blob_t mmap_read(void *stream, apk_blob_t token)
ret = mbs->left; ret = mbs->left;
mbs->left = APK_BLOB_NULL; mbs->left = APK_BLOB_NULL;
mbs->bs.flags |= APK_BSTREAM_EOF;
return ret; return ret;
} }

View File

@ -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; struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
unsigned char calculated[EVP_MAX_MD_SIZE]; unsigned char calculated[EVP_MAX_MD_SIZE];
int r; int r, end_of_control;
switch (part) { if ((part == APK_MPART_DATA) ||
case APK_MPART_DATA: (part == APK_MPART_BOUNDARY && sctx->data_started))
EVP_DigestUpdate(&sctx->mdctx, data.ptr, data.len); goto update_digest;
break;
case APK_MPART_BOUNDARY:
EVP_DigestUpdate(&sctx->mdctx, data.ptr, data.len);
/* We are not interested about checksums of signature, /* Still in signature blocks? */
* reset checksum if we are still in signatures */ if (!sctx->control_started)
if (!sctx->control_started) { goto reset_digest;
EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL);
EVP_DigestInit_ex(&sctx->mdctx, sctx->md, NULL); /* Grab state and mark all remaining block as data */
return 0; 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 (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?. */ r = EVP_VerifyFinal(&sctx->mdctx,
if ((!sctx->control_started) || sctx->data_started) (unsigned char *) sctx->signature.data.ptr,
return 0; sctx->signature.data.len,
sctx->signature.pkey);
/* End of control block, make sure rest is handled as data */ if (r != 1)
sctx->data_started = 1; return -EKEYREJECTED;
if (!sctx->has_data_checksum) sctx->control_verified = 1;
return 0; if (!sctx->has_data_checksum && part == APK_MPART_END)
sctx->data_verified = 1;
/* Verify the signature if we have public key */ break;
if (sctx->action == APK_SIGN_VERIFY) { case APK_SIGN_VERIFY_IDENTITY:
if (sctx->signature.pkey == NULL) { /* Reset digest for hashing data */
if (!(apk_flags & APK_ALLOW_UNTRUSTED)) EVP_DigestFinal_ex(&sctx->mdctx, calculated, NULL);
return -ENOKEY; if (memcmp(calculated, sctx->identity.data,
} else { sctx->identity.type) != 0)
r = EVP_VerifyFinal(&sctx->mdctx, return -EKEYREJECTED;
(unsigned char *) sctx->signature.data.ptr, sctx->control_verified = 1;
sctx->signature.data.len, if (!sctx->has_data_checksum && part == APK_MPART_END)
sctx->signature.pkey); sctx->data_verified = 1;
if (r != 1) break;
return -EKEYREJECTED; case APK_SIGN_GENERATE:
case APK_SIGN_GENERATE_V1:
sctx->control_verified = 1; /* Package identity is the checksum */
} sctx->identity.type = EVP_MD_CTX_size(&sctx->mdctx);
EVP_DigestInit_ex(&sctx->mdctx, sctx->md, NULL); EVP_DigestFinal_ex(&sctx->mdctx, sctx->identity.data, NULL);
return 0; if (sctx->action == APK_SIGN_GENERATE &&
} 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(&sctx->mdctx);
EVP_DigestFinal_ex(&sctx->mdctx, sctx->identity.data, NULL);
return -ECANCELED; 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;
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;
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; 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; return 0;
} }

View File

@ -20,6 +20,7 @@ static int verify_main(void *ctx, int argc, char **argv)
struct apk_istream *is; struct apk_istream *is;
int i, r, ok, rc = 0; int i, r, ok, rc = 0;
apk_flags |= APK_ALLOW_UNTRUSTED;
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL); apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL);
is = apk_bstream_gunzip_mpart(apk_bstream_from_file(argv[i]), 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); is->close(is);
ok = sctx.control_verified && sctx.data_verified; ok = sctx.control_verified && sctx.data_verified;
if (apk_verbosity >= 1) if (apk_verbosity >= 1)
apk_message("%s: %s", argv[i], apk_message("%s: %d - %s", argv[i], r,
ok ? "OK" : ok ? "OK" :
sctx.data_verified ? "UNTRUSTED" : "FAILED"); sctx.data_verified ? "UNTRUSTED" : "FAILED");
if (!ok) if (!ok)