From 0d9053423696ff6077df88ccafd5058ba327079e Mon Sep 17 00:00:00 2001 From: Duncan Overbruck Date: Mon, 10 Feb 2020 01:54:52 +0100 Subject: [PATCH] libxbps: ABI/API break due to hash function changes --- bin/xbps-create/main.c | 15 +++-- bin/xbps-digest/main.c | 14 ++--- bin/xbps-fetch/main.c | 16 ++++-- bin/xbps-pkgdb/check.c | 2 +- bin/xbps-pkgdb/check_pkg_files.c | 6 +- bin/xbps-remove/clean-cache.c | 2 +- bin/xbps-rindex/index-add.c | 7 +-- bin/xbps-rindex/index-clean.c | 2 +- bin/xbps-rindex/sign.c | 15 ++--- bin/xbps-uhelper/main.c | 7 ++- include/xbps.h.in | 20 ++++--- lib/download.c | 24 ++++---- lib/package_config_files.c | 11 +--- lib/package_register.c | 6 +- lib/transaction_fetch.c | 10 ++-- lib/transaction_files.c | 3 +- lib/util_hash.c | 94 +++++++++++++++++++++----------- lib/verifysig.c | 5 +- 18 files changed, 141 insertions(+), 118 deletions(-) diff --git a/bin/xbps-create/main.c b/bin/xbps-create/main.c index 7a82bca7..7ecbdc27 100644 --- a/bin/xbps-create/main.c +++ b/bin/xbps-create/main.c @@ -55,7 +55,8 @@ struct xentry { TAILQ_ENTRY(xentry) entries; uint64_t mtime; uint64_t size; - char *file, *type, *target, *hash; + char *file, *type, *target; + char sha256[XBPS_SHA256_SIZE]; ino_t inode; }; @@ -317,6 +318,7 @@ ftw_cb(const char *fpath, const struct stat *sb, const struct dirent *dir UNUSED xbps_dictionary_t fileinfo = NULL; const char *filep = NULL; char *buf, *p, *p2, *dname; + char sha256[XBPS_SHA256_SIZE]; ssize_t r; /* Ignore metadata files generated by xbps-src and destdir */ @@ -480,12 +482,9 @@ ftw_cb(const char *fpath, const struct stat *sb, const struct dirent *dir UNUSED } assert(xe->type); - if ((p = xbps_file_hash(fpath)) == NULL) - die("failed to process hash for %s:", fpath); - xbps_dictionary_set_cstring(fileinfo, "sha256", p); - free(p); - if ((xe->hash = xbps_file_hash(fpath)) == NULL) + if (!xbps_file_sha256(xe->sha256, sizeof sha256, fpath)) die("failed to process hash for %s:", fpath); + xbps_dictionary_set_cstring(fileinfo, "sha256", xe->sha256); xbps_dictionary_set_uint64(fileinfo, "inode", sb->st_ino); xe->inode = sb->st_ino; @@ -607,8 +606,8 @@ process_xentry(const char *key, const char *mutable_files) xbps_dictionary_set_cstring(d, "file", p); if (xe->target) xbps_dictionary_set_cstring(d, "target", xe->target); - if (xe->hash) - xbps_dictionary_set_cstring(d, "sha256", xe->hash); + if (*xe->sha256) + xbps_dictionary_set_cstring(d, "sha256", xe->sha256); if (xe->mtime) xbps_dictionary_set_uint64(d, "mtime", xe->mtime); if (xe->size) diff --git a/bin/xbps-digest/main.c b/bin/xbps-digest/main.c index 9b3f0cef..093e42e5 100644 --- a/bin/xbps-digest/main.c +++ b/bin/xbps-digest/main.c @@ -53,7 +53,7 @@ int main(int argc, char **argv) { int c; - char *hash = NULL; + char sha256[XBPS_SHA256_SIZE]; const char *mode = NULL, *progname = argv[0]; const struct option longopts[] = { { NULL, 0, NULL, 0 } @@ -84,23 +84,19 @@ main(int argc, char **argv) } if (argc < 1) { - hash = xbps_file_hash("/dev/stdin"); - if (hash == NULL) + if (!xbps_file_sha256(sha256, sizeof sha256, "/dev/stdin")) exit(EXIT_FAILURE); - printf("%s\n", hash); - free(hash); + printf("%s\n", sha256); } else { for (int i = 0; i < argc; i++) { - hash = xbps_file_hash(argv[i]); - if (hash == NULL) { + if (!xbps_file_sha256(sha256, sizeof sha256, argv[i])) { fprintf(stderr, "%s: couldn't get hash for %s (%s)\n", progname, argv[i], strerror(errno)); exit(EXIT_FAILURE); } - printf("%s\n", hash); - free(hash); + printf("%s\n", sha256); } } exit(EXIT_SUCCESS); diff --git a/bin/xbps-fetch/main.c b/bin/xbps-fetch/main.c index 17be3e90..6b5b0f39 100644 --- a/bin/xbps-fetch/main.c +++ b/bin/xbps-fetch/main.c @@ -138,13 +138,13 @@ main(int argc, char **argv) } for (int i = 0; i < argc; i++) { - unsigned char *digest = NULL; + unsigned char digest[XBPS_SHA256_DIGEST_SIZE]; if (i > 0 || !filename) filename = fname(argv[i]); if (shasum) { - rv = xbps_fetch_file_dest_digest(&xh, argv[i], filename, verbose ? "v" : "", &digest); + rv = xbps_fetch_file_dest_sha256(&xh, argv[i], filename, verbose ? "v" : "", digest, sizeof digest); } else { rv = xbps_fetch_file_dest(&xh, argv[i], filename, verbose ? "v" : ""); } @@ -153,15 +153,19 @@ main(int argc, char **argv) fprintf(stderr, "%s: %s\n", argv[i], xbps_fetch_error_string()); } else if (rv == 0) { fprintf(stderr, "%s: file is identical with remote.\n", argv[i]); - if (shasum) - digest = xbps_file_hash_raw(filename); + if (shasum) { + if (!xbps_file_sha256_raw(digest, sizeof digest, filename)) { + xbps_error_printf("%s: failed to hash libxbps: %s: %s\n", + progname, filename, strerror(rv)); + *digest = '\0'; + } + } } else { rv = 0; } - if (digest != NULL) { + if (*digest) { print_digest(digest, SHA256_DIGEST_LENGTH); printf(" %s\n", filename); - free(digest); } } diff --git a/bin/xbps-pkgdb/check.c b/bin/xbps-pkgdb/check.c index 0da54ba1..061d521c 100644 --- a/bin/xbps-pkgdb/check.c +++ b/bin/xbps-pkgdb/check.c @@ -102,7 +102,7 @@ check_pkg_integrity(struct xbps_handle *xhp, free(buf); return -1; } - rv = xbps_file_hash_check(buf, sha256); + rv = xbps_file_sha256_check(buf, sha256); free(buf); if (rv == ENOENT) { xbps_dictionary_remove(opkgd, "metafile-sha256"); diff --git a/bin/xbps-pkgdb/check_pkg_files.c b/bin/xbps-pkgdb/check_pkg_files.c index 742f0fd8..80855e48 100644 --- a/bin/xbps-pkgdb/check_pkg_files.c +++ b/bin/xbps-pkgdb/check_pkg_files.c @@ -99,9 +99,9 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg) if (xhp->noextract && xbps_patterns_match(xhp->noextract, file)) continue; path = xbps_xasprintf("%s/%s", xhp->rootdir, file); - xbps_dictionary_get_cstring_nocopy(obj, - "sha256", &sha256); - rv = xbps_file_hash_check(path, sha256); + xbps_dictionary_get_cstring_nocopy(obj, + "sha256", &sha256); + rv = xbps_file_sha256_check(path, sha256); switch (rv) { case 0: if (check_file_mtime(obj, pkgname, path)) { diff --git a/bin/xbps-remove/clean-cache.c b/bin/xbps-remove/clean-cache.c index b3e00622..43ff6057 100644 --- a/bin/xbps-remove/clean-cache.c +++ b/bin/xbps-remove/clean-cache.c @@ -72,7 +72,7 @@ cleaner_cb(struct xbps_handle *xhp, xbps_object_t obj, if (repo_pkgd) { xbps_dictionary_get_cstring_nocopy(repo_pkgd, "filename-sha256", &rsha256); - if (xbps_file_hash_check(binpkg, rsha256) == 0) { + if (xbps_file_sha256_check(binpkg, rsha256) == 0) { /* hash matched */ return 0; } diff --git a/bin/xbps-rindex/index-add.c b/bin/xbps-rindex/index-add.c index 60ea0063..15dac9cc 100644 --- a/bin/xbps-rindex/index-add.c +++ b/bin/xbps-rindex/index-add.c @@ -252,7 +252,8 @@ index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force */ for (int i = args; i < argmax; i++) { const char *arch = NULL, *pkg = argv[i]; - char *sha256 = NULL, *pkgver = NULL; + char *pkgver = NULL; + char sha256[XBPS_SHA256_SIZE]; char pkgname[XBPS_NAME_SIZE]; assert(pkg); @@ -331,7 +332,7 @@ index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force * - filename-size * - filename-sha256 */ - if ((sha256 = xbps_file_hash(pkg)) == NULL) { + if (!xbps_file_sha256(sha256, sizeof sha256, pkg)) { xbps_object_release(binpkgd); free(pkgver); rv = EINVAL; @@ -339,12 +340,10 @@ index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force } if (!xbps_dictionary_set_cstring(binpkgd, "filename-sha256", sha256)) { xbps_object_release(binpkgd); - free(sha256); free(pkgver); rv = EINVAL; goto out; } - free(sha256); if (stat(pkg, &st) == -1) { xbps_object_release(binpkgd); free(pkgver); diff --git a/bin/xbps-rindex/index-clean.c b/bin/xbps-rindex/index-clean.c index d2fa62e9..9e8cdcdb 100644 --- a/bin/xbps-rindex/index-clean.c +++ b/bin/xbps-rindex/index-clean.c @@ -77,7 +77,7 @@ idx_cleaner_cb(struct xbps_handle *xhp, */ xbps_dictionary_get_cstring_nocopy(obj, "filename-sha256", &sha256); - if (xbps_file_hash_check(filen, sha256) != 0) { + if (xbps_file_sha256_check(filen, sha256) != 0) { if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) goto out; xbps_dictionary_remove(dest, pkgname); diff --git a/bin/xbps-rindex/sign.c b/bin/xbps-rindex/sign.c index 4a714bb9..666f7e24 100644 --- a/bin/xbps-rindex/sign.c +++ b/bin/xbps-rindex/sign.c @@ -97,25 +97,26 @@ static bool rsa_sign_file(RSA *rsa, const char *file, unsigned char **sigret, unsigned int *siglen) { - unsigned char *sha256; + unsigned char digest[XBPS_SHA256_DIGEST_SIZE]; - sha256 = xbps_file_hash_raw(file); - if(!sha256) + if (!xbps_file_sha256_raw(digest, sizeof digest, file)) return false; if ((*sigret = calloc(1, RSA_size(rsa) + 1)) == NULL) { - free(sha256); return false; } - if (!RSA_sign(NID_sha1, sha256, SHA256_DIGEST_LENGTH, + /* + * XXX: NID_sha1 is wrong, doesn't make it any weaker + * but the ASN1 is wrong, OpenSSL/LibreSSL doesn't care. + * Other implementations like golang fail because of this. + */ + if (!RSA_sign(NID_sha1, digest, XBPS_SHA256_DIGEST_SIZE, *sigret, siglen, rsa)) { - free(sha256); free(*sigret); return false; } - free(sha256); return true; } diff --git a/bin/xbps-uhelper/main.c b/bin/xbps-uhelper/main.c index 18c29757..6482e20c 100644 --- a/bin/xbps-uhelper/main.c +++ b/bin/xbps-uhelper/main.c @@ -285,19 +285,20 @@ main(int argc, char **argv) printf("%s\n", XBPS_SYSDEFCONF_PATH); } else if (strcmp(argv[0], "digest") == 0) { + char sha256[XBPS_SHA256_SIZE]; + /* Prints SHA256 hashes for specified files */ if (argc < 2) usage(); for (int i = 1; i < argc; i++) { - filename = xbps_file_hash(argv[i]); - if (filename == NULL) { + if (!xbps_file_sha256(sha256, sizeof sha256, argv[i])) { fprintf(stderr, "E: couldn't get hash for %s (%s)\n", argv[i], strerror(errno)); exit(EXIT_FAILURE); } - printf("%s\n", filename); + printf("%s\n", sha256); } } else if (strcmp(argv[0], "fetch") == 0) { /* Fetch a file from specified URL */ diff --git a/include/xbps.h.in b/include/xbps.h.in index 00dfa502..2ff11036 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -51,7 +51,7 @@ * * This header documents the full API for the XBPS Library. */ -#define XBPS_API_VERSION "20200208" +#define XBPS_API_VERSION "20200210" #ifndef XBPS_VERSION #define XBPS_VERSION "UNSET" @@ -258,6 +258,9 @@ */ #define XBPS_FETCH_TIMEOUT 30 +#define XBPS_SHA256_DIGEST_SIZE 32 +#define XBPS_SHA256_SIZE 64+1 + #ifdef __cplusplus extern "C" { #endif @@ -763,8 +766,8 @@ int xbps_fetch_file(struct xbps_handle *xhp, const char *uri, * @return -1 on error, 0 if not downloaded (because local/remote size/mtime * do not match) and 1 if downloaded successfully. **/ -int xbps_fetch_file_digest(struct xbps_handle *xhp, const char *uri, - const char *flags, unsigned char **digestp); +int xbps_fetch_file_sha256(struct xbps_handle *xhp, const char *uri, + const char *flags, unsigned char *digest, size_t digestlen); /** * Download a file from a remote URL to current working directory, @@ -794,8 +797,9 @@ int xbps_fetch_file_dest(struct xbps_handle *xhp, const char *uri, * @return -1 on error, 0 if not downloaded (because local/remote size/mtime * do not match) and 1 if downloaded successfully. **/ -int xbps_fetch_file_dest_digest(struct xbps_handle *xhp, const char *uri, - const char *filename, const char *flags, unsigned char **digestp); +int xbps_fetch_file_dest_sha256(struct xbps_handle *xhp, const char *uri, + const char *filename, const char *flags, + unsigned char *digest, size_t digestlen); /** * Returns last error string reported by xbps_fetch_file(). @@ -1859,7 +1863,7 @@ bool xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filele * is set appropiately. The pointer should be free(3)d when it's no * longer needed. */ -char *xbps_file_hash(const char *file); +bool xbps_file_sha256(char *dst, size_t dstlen, const char *file); /** * Returns a raw byte buffer with the sha256 hash for the file specified @@ -1870,7 +1874,7 @@ char *xbps_file_hash(const char *file); * is set appropiately. The pointer should be free(3)d when it's no * longer needed. */ -unsigned char *xbps_file_hash_raw(const char *file); +bool xbps_file_sha256_raw(unsigned char *dst, size_t dstlen, const char *file); /** * Compares the sha256 hash of the file \a file with the sha256 @@ -1882,7 +1886,7 @@ unsigned char *xbps_file_hash_raw(const char *file); * @return 0 if \a file and \a sha256 have the same hash, ERANGE * if it differs, or any other errno value on error. */ -int xbps_file_hash_check(const char *file, const char *sha256); +int xbps_file_sha256_check(const char *file, const char *sha256); /** * Verifies the RSA signature \a sigfile against \a digest with the diff --git a/lib/download.c b/lib/download.c index a7f85223..ce8f2a79 100644 --- a/lib/download.c +++ b/lib/download.c @@ -93,7 +93,7 @@ xbps_fetch_error_string(void) } int -xbps_fetch_file_dest_digest(struct xbps_handle *xhp, const char *uri, const char *filename, const char *flags, unsigned char **digestp) +xbps_fetch_file_dest_sha256(struct xbps_handle *xhp, const char *uri, const char *filename, const char *flags, unsigned char *digest, size_t digestlen) { struct stat st, st_tmpfile, *stp; struct url *url = NULL; @@ -106,16 +106,13 @@ xbps_fetch_file_dest_digest(struct xbps_handle *xhp, const char *uri, const char char fetch_flags[8]; int fd = -1, rv = 0; bool refetch = false, restart = false; - unsigned char *digest = NULL; SHA256_CTX sha256; assert(xhp); assert(uri); - if (digestp) { - digest = malloc(SHA256_DIGEST_LENGTH); - if (!digest) - return -1; + if (digest) { + assert(digestlen != XBPS_SHA256_DIGEST_SIZE); SHA256_Init(&sha256); } @@ -317,10 +314,8 @@ rename_file: } rv = 1; - if (digest) { + if (digest) SHA256_Final(digest, &sha256); - *digestp = digest; - } fetch_file_out: if (fio != NULL) @@ -339,12 +334,12 @@ int xbps_fetch_file_dest(struct xbps_handle *xhp, const char *uri, const char *filename, const char *flags) { - return xbps_fetch_file_dest_digest(xhp, uri, filename, flags, NULL); + return xbps_fetch_file_dest_sha256(xhp, uri, filename, flags, NULL, 0); } int -xbps_fetch_file_digest(struct xbps_handle *xhp, const char *uri, - const char *flags, unsigned char **digestp) +xbps_fetch_file_sha256(struct xbps_handle *xhp, const char *uri, + const char *flags, unsigned char *digest, size_t digestlen) { const char *filename; /* @@ -354,11 +349,12 @@ xbps_fetch_file_digest(struct xbps_handle *xhp, const char *uri, return -1; filename++; - return xbps_fetch_file_dest_digest(xhp, uri, filename, flags, digestp); + return xbps_fetch_file_dest_sha256(xhp, uri, filename, flags, + digest, digestlen); } int xbps_fetch_file(struct xbps_handle *xhp, const char *uri, const char *flags) { - return xbps_fetch_file_digest(xhp, uri, flags, NULL); + return xbps_fetch_file_sha256(xhp, uri, flags, NULL, 0); } diff --git a/lib/package_config_files.c b/lib/package_config_files.c index d0d7bf33..ac3b9d95 100644 --- a/lib/package_config_files.c +++ b/lib/package_config_files.c @@ -69,7 +69,7 @@ xbps_entry_install_conf_file(struct xbps_handle *xhp, xbps_object_t obj, obj2; xbps_object_iterator_t iter, iter2; const char *version = NULL, *cffile, *sha256_new = NULL; - char buf[PATH_MAX], *sha256_cur = NULL, *sha256_orig = NULL; + char buf[PATH_MAX], sha256_cur[XBPS_SHA256_SIZE], *sha256_orig = NULL; int rv = 0; assert(xbps_object_type(binpkg_filesd) == XBPS_TYPE_DICTIONARY); @@ -139,9 +139,7 @@ xbps_entry_install_conf_file(struct xbps_handle *xhp, if (strcmp(entry_pname, buf)) { continue; } - sha256_cur = xbps_file_hash(buf); - xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new); - if (sha256_cur == NULL) { + if (!xbps_file_sha256(sha256_cur, sizeof sha256_cur, buf)) { if (errno == ENOENT) { /* * File not installed, install new one. @@ -155,6 +153,7 @@ xbps_entry_install_conf_file(struct xbps_handle *xhp, break; } } + xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new); /* * Orig = X, Curr = X, New = X * @@ -232,15 +231,11 @@ xbps_entry_install_conf_file(struct xbps_handle *xhp, rv = 1; break; } - free(sha256_cur); - sha256_cur = NULL; } out: if (sha256_orig) free(sha256_orig); - if (sha256_cur) - free(sha256_cur); xbps_object_iterator_release(iter); diff --git a/lib/package_register.c b/lib/package_register.c index f733e38d..f3a0caea 100644 --- a/lib/package_register.c +++ b/lib/package_register.c @@ -41,7 +41,8 @@ xbps_register_pkg(struct xbps_handle *xhp, xbps_dictionary_t pkgrd) struct tm tm; struct tm *tmp; const char *pkgver; - char *buf, *sha256; + char sha256[XBPS_SHA256_SIZE]; + char *buf; int rv = 0; bool autoinst = false; @@ -104,9 +105,8 @@ xbps_register_pkg(struct xbps_handle *xhp, xbps_dictionary_t pkgrd) * Create a hash for the pkg's metafile if it exists. */ buf = xbps_xasprintf("%s/.%s-files.plist", xhp->metadir, pkgname); - if ((sha256 = xbps_file_hash(buf))) { + if (xbps_file_sha256(sha256, sizeof sha256, buf)) { xbps_dictionary_set_cstring(pkgd, "metafile-sha256", sha256); - free(sha256); } free(buf); /* diff --git a/lib/transaction_fetch.c b/lib/transaction_fetch.c index e6749f68..92f1d37d 100644 --- a/lib/transaction_fetch.c +++ b/lib/transaction_fetch.c @@ -79,7 +79,7 @@ verify_binpkg(struct xbps_handle *xhp, xbps_dictionary_t pkgd) xbps_set_cb_state(xhp, XBPS_STATE_VERIFY, 0, pkgver, "%s: verifying SHA256 hash...", pkgver); xbps_dictionary_get_cstring_nocopy(pkgd, "filename-sha256", &sha256); - if ((rv = xbps_file_hash_check(binfile, sha256)) != 0) { + if ((rv = xbps_file_sha256_check(binfile, sha256)) != 0) { xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver, "%s: SHA256 hash is not valid: %s", pkgver, strerror(rv)); goto out; @@ -98,7 +98,7 @@ download_binpkg(struct xbps_handle *xhp, xbps_dictionary_t repo_pkgd) char buf[PATH_MAX]; char *sigsuffix; const char *pkgver, *arch, *fetchstr, *repoloc; - unsigned char *digest = NULL; + unsigned char digest[XBPS_SHA256_DIGEST_SIZE] = {0}; int rv = 0; xbps_dictionary_get_cstring_nocopy(repo_pkgd, "repository", &repoloc); @@ -129,7 +129,8 @@ download_binpkg(struct xbps_handle *xhp, xbps_dictionary_t repo_pkgd) xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD, 0, pkgver, "Downloading `%s' package (from `%s')...", pkgver, repoloc); - if ((rv = xbps_fetch_file_digest(xhp, buf, NULL, &digest)) == -1) { + if ((rv = xbps_fetch_file_sha256(xhp, buf, NULL, digest, + sizeof digest)) == -1) { rv = fetchLastErrCode ? fetchLastErrCode : errno; fetchstr = xbps_fetch_error_string(); xbps_set_cb_state(xhp, XBPS_STATE_DOWNLOAD_FAIL, rv, @@ -156,7 +157,7 @@ download_binpkg(struct xbps_handle *xhp, xbps_dictionary_t repo_pkgd) * If digest is not set, binary package was not downloaded, * i.e. 304 not modified, verify by file instead. */ - if (!digest) { + if (*digest) { *sigsuffix = '\0'; if (!xbps_verify_file_signature(repo, buf)) { rv = EPERM; @@ -175,7 +176,6 @@ download_binpkg(struct xbps_handle *xhp, xbps_dictionary_t repo_pkgd) *sigsuffix = '\0'; (void)remove(buf); } - free(digest); } if (rv == EPERM) { diff --git a/lib/transaction_files.c b/lib/transaction_files.c index 573eb336..2fe39d95 100644 --- a/lib/transaction_files.c +++ b/lib/transaction_files.c @@ -75,6 +75,7 @@ itemhash(const char *file) assert(file); + /* XXX: runtime error: left shift of negative value -1581911230 */ for (i = 0; file[i]; ++i) hv = (hv << 5) ^ (hv >> 23) ^ file[i]; @@ -321,7 +322,7 @@ collect_obsoletes(struct xbps_handle *xhp) * Skip unexisting files and keep files with hash mismatch. */ if (item->old.sha256) { - rv = xbps_file_hash_check(item->file, item->old.sha256); + rv = xbps_file_sha256_check(item->file, item->old.sha256); switch (rv) { case 0: /* hash matches, we can safely delete and/or overwrite it */ diff --git a/lib/util_hash.c b/lib/util_hash.c index 985e9063..5a863f3d 100644 --- a/lib/util_hash.c +++ b/lib/util_hash.c @@ -108,65 +108,93 @@ xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filelen) return true; } -unsigned char * -xbps_file_hash_raw(const char *file) +bool +xbps_file_sha256_raw(unsigned char *dst, size_t dstlen, const char *file) { int fd; ssize_t len; - unsigned char *digest, buf[65536]; + char buf[65536]; SHA256_CTX sha256; + assert(dstlen == SHA256_DIGEST_LENGTH); + if ((fd = open(file, O_RDONLY)) < 0) - return NULL; - digest = malloc(SHA256_DIGEST_LENGTH); - assert(digest); + return false; + SHA256_Init(&sha256); + while ((len = read(fd, buf, sizeof(buf))) > 0) SHA256_Update(&sha256, buf, len); - if(len < 0) { - free(digest); - return NULL; - } - SHA256_Final(digest, &sha256); + (void)close(fd); - return digest; + if(len == -1) + return false; + + SHA256_Final(dst, &sha256); + + return true; } -char * -xbps_file_hash(const char *file) +bool +xbps_file_sha256(char *dst, size_t dstlen, const char *file) { - char *hash; - unsigned char *digest; + unsigned char digest[XBPS_SHA256_DIGEST_SIZE]; - if (!(digest = xbps_file_hash_raw(file))) - return NULL; + assert(dstlen == XBPS_SHA256_SIZE); - hash = malloc(SHA256_DIGEST_LENGTH * 2 + 1); - assert(hash); - digest2string(digest, hash, SHA256_DIGEST_LENGTH); - free(digest); + if (!xbps_file_sha256_raw(digest, sizeof digest, file)) + return false; - return hash; + digest2string(digest, dst, XBPS_SHA256_DIGEST_SIZE); + + return true; +} + +static bool +sha256_digest_compare(const char *sha256, size_t shalen, + const unsigned char *digest, size_t digestlen) +{ + assert(digestlen == XBPS_SHA256_DIGEST_SIZE); + assert(shalen == XBPS_SHA256_SIZE - 1); + + if (shalen != XBPS_SHA256_SIZE -1) + return false; + + for (; *sha256;) { + if (*digest / 16 < 10) { + if (*sha256++ != '0' + *digest / 16) + return false; + } else { + if (*sha256++ != 'a' + *digest / 16 - 10) + return false; + } + if (*digest % 16 < 10) { + if (*sha256++ != '0' + *digest % 16) + return false; + } else { + if (*sha256++ != 'a' + *digest % 16 - 10) + return false; + } + digest++; + } + + return true; } int -xbps_file_hash_check(const char *file, const char *sha256) +xbps_file_sha256_check(const char *file, const char *sha256) { - char *res; + unsigned char digest[XBPS_SHA256_DIGEST_SIZE]; assert(file != NULL); assert(sha256 != NULL); - res = xbps_file_hash(file); - if (res == NULL) + if (!xbps_file_sha256_raw(digest, sizeof digest, file)) return errno; - if (strcmp(sha256, res)) { - free(res); + if (!sha256_digest_compare(sha256, strlen(sha256), digest, sizeof digest)) return ERANGE; - } - free(res); return 0; } @@ -226,10 +254,10 @@ xbps_file_hash_check_dictionary(struct xbps_handle *xhp, } if (strcmp(xhp->rootdir, "/") == 0) { - rv = xbps_file_hash_check(file, sha256d); + rv = xbps_file_sha256_check(file, sha256d); } else { buf = xbps_xasprintf("%s/%s", xhp->rootdir, file); - rv = xbps_file_hash_check(buf, sha256d); + rv = xbps_file_sha256_check(buf, sha256d); free(buf); } if (rv == 0) diff --git a/lib/verifysig.c b/lib/verifysig.c index 58729a37..56537989 100644 --- a/lib/verifysig.c +++ b/lib/verifysig.c @@ -137,10 +137,10 @@ bool xbps_verify_file_signature(struct xbps_repo *repo, const char *fname) { char sig[PATH_MAX]; - unsigned char *digest = NULL; + unsigned char digest[XBPS_SHA256_DIGEST_SIZE]; bool val = false; - if (!(digest = xbps_file_hash_raw(fname))) { + if (!xbps_file_sha256_raw(digest, sizeof digest, fname)) { xbps_dbg_printf(repo->xhp, "can't open file %s: %s\n", fname, strerror(errno)); return false; } @@ -148,6 +148,5 @@ xbps_verify_file_signature(struct xbps_repo *repo, const char *fname) snprintf(sig, sizeof sig, "%s.sig", fname); val = xbps_verify_signature(repo, sig, digest); - free(digest); return val; }