From f0cb9a891c1fbc3942035cc0426cb594e07e9cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedel=20Sch=C3=B6n?= Date: Tue, 23 Jan 2024 14:57:48 +0100 Subject: [PATCH 1/6] lib: replace deprecated SHA256_* with EPV --- lib/repo.c | 2 +- lib/util_hash.c | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/lib/repo.c b/lib/repo.c index 8d2aa6bd..54d660cb 100644 --- a/lib/repo.c +++ b/lib/repo.c @@ -58,7 +58,7 @@ xbps_repo_path_with_name(struct xbps_handle *xhp, const char *url, const char *n { assert(xhp); assert(url); - assert(strcmp(name, "repodata") == 0 || strcmp(name, "stagedata") == 0); + assert(strcmp(name, "repodata") == 0 || strcmp(name, "stagedata") == 0|| strcmp(name, "files") == 0); return xbps_xasprintf("%s/%s-%s", url, xhp->target_arch ? xhp->target_arch : xhp->native_arch, name); diff --git a/lib/util_hash.c b/lib/util_hash.c index 3ed38c52..c5f6b793 100644 --- a/lib/util_hash.c +++ b/lib/util_hash.c @@ -35,10 +35,16 @@ #include #include -#include +#include #include "xbps_api_impl.h" +#if OPENSSL_VERSION_NUMBER < 0x10100000L +# define EVP_MD_CTX_new EVP_MD_CTX_create +# define EVP_MD_CTX_free EVP_MD_CTX_destroy +#endif + + /** * @file lib/util.c * @brief Utility routines @@ -113,15 +119,13 @@ xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filelen) } bool -xbps_file_sha256_raw(unsigned char *dst, size_t dstlen, const char *file) -{ +xbps_file_sha256_raw(unsigned char *dst, unsigned int dstlen, const char *file) { int fd; ssize_t len; char buf[65536]; - SHA256_CTX sha256; + EVP_MD_CTX *mdctx; - assert(dstlen >= XBPS_SHA256_DIGEST_SIZE); - if (dstlen < XBPS_SHA256_DIGEST_SIZE) { + if ((int) dstlen < EVP_MD_size(EVP_sha256())) { errno = ENOBUFS; return false; } @@ -129,17 +133,22 @@ xbps_file_sha256_raw(unsigned char *dst, size_t dstlen, const char *file) if ((fd = open(file, O_RDONLY)) < 0) return false; - SHA256_Init(&sha256); + if((mdctx = EVP_MD_CTX_new()) == NULL) + return false; + + if(EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) + return false; while ((len = read(fd, buf, sizeof(buf))) > 0) - SHA256_Update(&sha256, buf, len); + if(EVP_DigestUpdate(mdctx, buf, len) != false) + return false; - (void)close(fd); + close(fd); - if(len == -1) + if(EVP_DigestFinal_ex(mdctx, dst, &dstlen) != 1) return false; - SHA256_Final(dst, &sha256); + EVP_MD_CTX_free(mdctx); return true; } From ea55f11992f0a0ad89b90c05c52b22b918a02cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedel=20Sch=C3=B6n?= Date: Tue, 23 Jan 2024 18:46:13 +0100 Subject: [PATCH 2/6] lib,bin: generalize hashing --- bin/xbps-create/main.c | 2 +- bin/xbps-digest/main.c | 4 +- bin/xbps-fetch/main.c | 2 +- bin/xbps-pkgdb/check.c | 2 +- bin/xbps-pkgdb/check_pkg_files.c | 2 +- bin/xbps-query/ownedby.c | 112 +++++++++++++++---------------- bin/xbps-remove/clean-cache.c | 2 +- bin/xbps-rindex/index-add.c | 2 +- bin/xbps-rindex/index-clean.c | 2 +- bin/xbps-rindex/sign.c | 2 +- bin/xbps-uhelper/main.c | 2 +- include/xbps.h.in | 15 ++++- lib/package_config_files.c | 2 +- lib/package_register.c | 2 +- lib/transaction_fetch.c | 2 +- lib/transaction_files.c | 2 +- lib/util_hash.c | 46 +++++++++---- lib/verifysig.c | 2 +- 18 files changed, 115 insertions(+), 90 deletions(-) diff --git a/bin/xbps-create/main.c b/bin/xbps-create/main.c index b187b22d..bc41873e 100644 --- a/bin/xbps-create/main.c +++ b/bin/xbps-create/main.c @@ -528,7 +528,7 @@ ftw_cb(const char *fpath, const struct stat *sb, const struct dirent *dir UNUSED xe->type = ENTRY_TYPE_FILES; } - if (!xbps_file_sha256(xe->sha256, sizeof sha256, fpath)) + if (!xbps_file_hash(XBPS_HASH_SHA256, xe->sha256, sizeof sha256, fpath)) die("failed to process hash for: %s", fpath); xbps_dictionary_set_cstring(fileinfo, "sha256", xe->sha256); diff --git a/bin/xbps-digest/main.c b/bin/xbps-digest/main.c index a197fb6a..229d4d86 100644 --- a/bin/xbps-digest/main.c +++ b/bin/xbps-digest/main.c @@ -89,13 +89,13 @@ main(int argc, char **argv) } if (argc < 1) { - if (!xbps_file_sha256(sha256, sizeof sha256, "/dev/stdin")) + if (!xbps_file_hash(XBPS_HASH_SHA256, sha256, sizeof sha256, "/dev/stdin")) exit(EXIT_FAILURE); printf("%s\n", sha256); } else { for (int i = 0; i < argc; i++) { - if (!xbps_file_sha256(sha256, sizeof sha256, argv[i])) { + if (!xbps_file_hash(XBPS_HASH_SHA256, sha256, sizeof sha256, argv[i])) { xbps_error_printf( "%s: couldn't get hash for %s (%s)\n", progname, argv[i], strerror(errno)); diff --git a/bin/xbps-fetch/main.c b/bin/xbps-fetch/main.c index e869489d..b2087220 100644 --- a/bin/xbps-fetch/main.c +++ b/bin/xbps-fetch/main.c @@ -169,7 +169,7 @@ main(int argc, char **argv) } else if (rv == 0) { xbps_warn_printf("%s: %s: file is identical with remote.\n", progname, argv[i]); if (shasum) { - if (!xbps_file_sha256_raw(digest, sizeof digest, filename)) { + if (!xbps_file_hash_raw(XBPS_HASH_SHA256, digest, sizeof digest, filename)) { xbps_error_printf("%s: failed to hash: %s: %s\n", progname, filename, strerror(rv)); failure = true; diff --git a/bin/xbps-pkgdb/check.c b/bin/xbps-pkgdb/check.c index f5dcf9da..406c1525 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 -ENOENT; } - rv = xbps_file_sha256_check(buf, sha256); + rv = xbps_file_hash_check(XBPS_HASH_SHA256, 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 e15e51c5..8b57f228 100644 --- a/bin/xbps-pkgdb/check_pkg_files.c +++ b/bin/xbps-pkgdb/check_pkg_files.c @@ -74,7 +74,7 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg) path = xbps_xasprintf("%s/%s", xhp->rootdir, file); xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256); - rv = xbps_file_sha256_check(path, sha256); + rv = xbps_file_hash_check(XBPS_HASH_SHA256, path, sha256); switch (rv) { case 0: free(path); diff --git a/bin/xbps-query/ownedby.c b/bin/xbps-query/ownedby.c index baa82c3b..6d2cb8ab 100644 --- a/bin/xbps-query/ownedby.c +++ b/bin/xbps-query/ownedby.c @@ -23,6 +23,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "defs.h" + #include #include #include @@ -33,26 +35,23 @@ #include #include #include - #include -#include "defs.h" struct ffdata { - bool rematch; - const char *pat, *repouri; - regex_t regex; - xbps_array_t allkeys; + bool rematch; + const char * pat, *repouri; + regex_t regex; + xbps_array_t allkeys; xbps_dictionary_t filesd; }; static void -match_files_by_pattern(xbps_dictionary_t pkg_filesd, - xbps_dictionary_keysym_t key, - struct ffdata *ffd, - const char *pkgver) -{ +match_files_by_pattern(xbps_dictionary_t pkg_filesd, + xbps_dictionary_keysym_t key, + struct ffdata* ffd, + const char* pkgver) { xbps_array_t array; - const char *keyname = NULL, *typestr = NULL; + const char * keyname = NULL, *typestr = NULL; keyname = xbps_dictionary_keysym_cstring_nocopy(key); @@ -68,7 +67,7 @@ match_files_by_pattern(xbps_dictionary_t pkg_filesd, array = xbps_dictionary_get_keysym(pkg_filesd, key); for (unsigned int i = 0; i < xbps_array_count(array); i++) { xbps_object_t obj; - const char *filestr = NULL, *tgt = NULL; + const char * filestr = NULL, *tgt = NULL; obj = xbps_array_get(array, i); xbps_dictionary_get_cstring_nocopy(obj, "file", &filestr); @@ -78,37 +77,36 @@ match_files_by_pattern(xbps_dictionary_t pkg_filesd, if (ffd->rematch) { if (regexec(&ffd->regex, filestr, 0, 0, 0) == 0) { printf("%s: %s%s%s (%s)\n", - pkgver, filestr, - tgt ? " -> " : "", - tgt ? tgt : "", - typestr); + pkgver, filestr, + tgt ? " -> " : "", + tgt ? tgt : "", + typestr); } } else { if ((fnmatch(ffd->pat, filestr, FNM_PERIOD)) == 0) { printf("%s: %s%s%s (%s)\n", - pkgver, filestr, - tgt ? " -> " : "", - tgt ? tgt : "", - typestr); + pkgver, filestr, + tgt ? " -> " : "", + tgt ? tgt : "", + typestr); } } } } static int -ownedby_pkgdb_cb(struct xbps_handle *xhp, - xbps_object_t obj, - const char *obj_key UNUSED, - void *arg, - bool *done UNUSED) -{ +ownedby_pkgdb_cb(struct xbps_handle* xhp, + xbps_object_t obj, + const char* obj_key UNUSED, + void* arg, + bool* done UNUSED) { xbps_dictionary_t pkgmetad; - xbps_array_t files_keys; - struct ffdata *ffd = arg; - const char *pkgver = NULL; + xbps_array_t files_keys; + struct ffdata* ffd = arg; + const char* pkgver = NULL; - (void)obj_key; - (void)done; + (void) obj_key; + (void) done; xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); pkgmetad = xbps_pkgdb_get_pkg_files(xhp, pkgver); @@ -118,7 +116,7 @@ ownedby_pkgdb_cb(struct xbps_handle *xhp, files_keys = xbps_dictionary_all_keys(pkgmetad); for (unsigned int i = 0; i < xbps_array_count(files_keys); i++) { match_files_by_pattern(pkgmetad, - xbps_array_get(files_keys, i), ffd, pkgver); + xbps_array_get(files_keys, i), ffd, pkgver); } xbps_object_release(pkgmetad); xbps_object_release(files_keys); @@ -128,18 +126,17 @@ ownedby_pkgdb_cb(struct xbps_handle *xhp, static int -repo_match_cb(struct xbps_handle *xhp, - xbps_object_t obj, - const char *key UNUSED, - void *arg, - bool *done UNUSED) -{ - char bfile[PATH_MAX]; +repo_match_cb(struct xbps_handle* xhp, + xbps_object_t obj, + const char* key UNUSED, + void* arg, + bool* done UNUSED) { + char bfile[PATH_MAX]; xbps_dictionary_t filesd; - xbps_array_t files_keys; - struct ffdata *ffd = arg; - const char *pkgver = NULL; - int r; + xbps_array_t files_keys; + struct ffdata* ffd = arg; + const char* pkgver = NULL; + int r; xbps_dictionary_set_cstring_nocopy(obj, "repository", ffd->repouri); xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); @@ -152,13 +149,13 @@ repo_match_cb(struct xbps_handle *xhp, filesd = xbps_archive_fetch_plist(bfile, "/files.plist"); if (!filesd) { xbps_error_printf("%s: couldn't fetch files.plist from %s: %s\n", - pkgver, bfile, strerror(errno)); + pkgver, bfile, strerror(errno)); return EINVAL; } files_keys = xbps_dictionary_all_keys(filesd); for (unsigned int i = 0; i < xbps_array_count(files_keys); i++) { match_files_by_pattern(filesd, - xbps_array_get(files_keys, i), ffd, pkgver); + xbps_array_get(files_keys, i), ffd, pkgver); } xbps_object_release(files_keys); xbps_object_release(filesd); @@ -167,32 +164,29 @@ repo_match_cb(struct xbps_handle *xhp, } static int -repo_ownedby_cb(struct xbps_repo *repo, void *arg, bool *done UNUSED) -{ - xbps_array_t allkeys; - struct ffdata *ffd = arg; - int rv; +repo_ownedby_cb(struct xbps_repo* repo, void* arg, bool* done UNUSED) { + xbps_array_t allkeys; + struct ffdata* ffd = arg; + int rv; ffd->repouri = repo->uri; - allkeys = xbps_dictionary_all_keys(repo->idx); - rv = xbps_array_foreach_cb_multi(repo->xhp, allkeys, repo->idx, repo_match_cb, ffd); + allkeys = xbps_dictionary_all_keys(repo->idx); + rv = xbps_array_foreach_cb_multi(repo->xhp, allkeys, repo->idx, repo_match_cb, ffd); xbps_object_release(allkeys); return rv; } -int -ownedby(struct xbps_handle *xhp, const char *pat, bool repo, bool regex) -{ +int ownedby(struct xbps_handle* xhp, const char* pat, bool repo, bool regex) { struct ffdata ffd; - int rv; + int rv; ffd.rematch = false; - ffd.pat = pat; + ffd.pat = pat; if (regex) { ffd.rematch = true; - if (regcomp(&ffd.regex, ffd.pat, REG_EXTENDED|REG_NOSUB|REG_ICASE) != 0) + if (regcomp(&ffd.regex, ffd.pat, REG_EXTENDED | REG_NOSUB | REG_ICASE) != 0) return EINVAL; } if (repo) diff --git a/bin/xbps-remove/clean-cache.c b/bin/xbps-remove/clean-cache.c index ea9caccb..1dd5f450 100644 --- a/bin/xbps-remove/clean-cache.c +++ b/bin/xbps-remove/clean-cache.c @@ -106,7 +106,7 @@ cleaner_cb(struct xbps_handle *xhp, xbps_object_t obj, if (pkgd) { xbps_dictionary_get_cstring_nocopy(pkgd, "filename-sha256", &rsha256); - r = xbps_file_sha256_check(binpkg, rsha256); + r = xbps_file_hash_check(XBPS_HASH_SHA256, binpkg, rsha256); if (r == 0) { /* hash matched */ return 0; diff --git a/bin/xbps-rindex/index-add.c b/bin/xbps-rindex/index-add.c index 00b3132c..6c989e24 100644 --- a/bin/xbps-rindex/index-add.c +++ b/bin/xbps-rindex/index-add.c @@ -334,7 +334,7 @@ index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force * - filename-size * - filename-sha256 */ - if (!xbps_file_sha256(sha256, sizeof sha256, pkg)) { + if (!xbps_file_hash(XBPS_HASH_SHA256, sha256, sizeof sha256, pkg)) { xbps_object_release(binpkgd); free(pkgver); rv = EINVAL; diff --git a/bin/xbps-rindex/index-clean.c b/bin/xbps-rindex/index-clean.c index 2226e19f..5543d262 100644 --- a/bin/xbps-rindex/index-clean.c +++ b/bin/xbps-rindex/index-clean.c @@ -80,7 +80,7 @@ idx_cleaner_cb(struct xbps_handle *xhp UNUSED, */ xbps_dictionary_get_cstring_nocopy(obj, "filename-sha256", &sha256); - if (xbps_file_sha256_check(filen, sha256) != 0) { + if (xbps_file_hash_check(XBPS_HASH_SHA256, 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 7e6cd2ce..a0258465 100644 --- a/bin/xbps-rindex/sign.c +++ b/bin/xbps-rindex/sign.c @@ -94,7 +94,7 @@ rsa_sign_file(RSA *rsa, const char *file, { unsigned char digest[XBPS_SHA256_DIGEST_SIZE]; - if (!xbps_file_sha256_raw(digest, sizeof digest, file)) + if (!xbps_file_hash_raw(XBPS_HASH_SHA256, digest, sizeof digest, file)) return false; if ((*sigret = calloc(1, RSA_size(rsa) + 1)) == NULL) { diff --git a/bin/xbps-uhelper/main.c b/bin/xbps-uhelper/main.c index 84eca5bf..336b5272 100644 --- a/bin/xbps-uhelper/main.c +++ b/bin/xbps-uhelper/main.c @@ -370,7 +370,7 @@ main(int argc, char **argv) usage(); for (i = 1; i < argc; i++) { - if (!xbps_file_sha256(sha256, sizeof sha256, argv[i])) { + if (!xbps_file_hash(XBPS_HASH_SHA256, sha256, sizeof sha256, argv[i])) { xbps_error_printf( "couldn't get hash for %s (%s)\n", argv[i], strerror(errno)); diff --git a/include/xbps.h.in b/include/xbps.h.in index 5ccd51e9..1541fe4f 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -1882,6 +1882,15 @@ char *xbps_xasprintf(const char *fmt, ...)__attribute__ ((format (printf, 1, 2)) */ bool xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filelen); +typedef enum xbps_hash_algorithm { + XBPS_HASH_SHA256, + XBPS_HASH_BLAKE2B256 +} xbps_hash_algorithm_t; + +int xbps_hash_size_raw(xbps_hash_algorithm_t type); + +int xbps_hash_size(xbps_hash_algorithm_t type); + /** * Computes a sha256 hex digest into \a dst of size \a len * from file \a file. @@ -1892,7 +1901,7 @@ bool xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filele * * @return true on success, false otherwise. */ -bool xbps_file_sha256(char *dst, size_t len, const char *file); +bool xbps_file_hash(xbps_hash_algorithm_t algo, char *dst, size_t len, const char *file); /** * Computes a sha256 binary digest into \a dst of size \a len @@ -1904,7 +1913,7 @@ bool xbps_file_sha256(char *dst, size_t len, const char *file); * * @return true on success, false otherwise. */ -bool xbps_file_sha256_raw(unsigned char *dst, size_t len, const char *file); +bool xbps_file_hash_raw(xbps_hash_algorithm_t algo, unsigned char *dst, unsigned int len, const char *file); /** * Compares the sha256 hash of the file \a file with the sha256 @@ -1916,7 +1925,7 @@ bool xbps_file_sha256_raw(unsigned char *dst, size_t len, 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_sha256_check(const char *file, const char *sha256); +int xbps_file_hash_check(xbps_hash_algorithm_t algo, const char *file, const char *sha256); /** * Verifies the RSA signature \a sigfile against \a digest with the diff --git a/lib/package_config_files.c b/lib/package_config_files.c index ea089866..cf3c71a7 100644 --- a/lib/package_config_files.c +++ b/lib/package_config_files.c @@ -143,7 +143,7 @@ xbps_entry_install_conf_file(struct xbps_handle *xhp, if (strcmp(entry_pname, buf)) { continue; } - if (!xbps_file_sha256(sha256_cur, sizeof sha256_cur, buf)) { + if (!xbps_file_hash(XBPS_HASH_SHA256, sha256_cur, sizeof sha256_cur, buf)) { if (errno == ENOENT) { /* * File not installed, install new one. diff --git a/lib/package_register.c b/lib/package_register.c index 5ea2f6f9..caaa8417 100644 --- a/lib/package_register.c +++ b/lib/package_register.c @@ -86,7 +86,7 @@ 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 (xbps_file_sha256(sha256, sizeof sha256, buf)) { + if (xbps_file_hash(XBPS_HASH_SHA256, sha256, sizeof sha256, buf)) { xbps_dictionary_set_cstring(pkgd, "metafile-sha256", sha256); } free(buf); diff --git a/lib/transaction_fetch.c b/lib/transaction_fetch.c index 22182e16..dc034f68 100644 --- a/lib/transaction_fetch.c +++ b/lib/transaction_fetch.c @@ -80,7 +80,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_sha256_check(binfile, sha256)) != 0) { + if ((rv = xbps_file_hash_check(XBPS_HASH_SHA256, binfile, sha256)) != 0) { xbps_set_cb_state(xhp, XBPS_STATE_VERIFY_FAIL, rv, pkgver, "%s: SHA256 hash is not valid: %s", pkgver, strerror(rv)); return rv; diff --git a/lib/transaction_files.c b/lib/transaction_files.c index 890b447a..45c56db6 100644 --- a/lib/transaction_files.c +++ b/lib/transaction_files.c @@ -312,7 +312,7 @@ collect_obsoletes(struct xbps_handle *xhp) * Skip unexisting files and keep files with hash mismatch. */ if (item->old.sha256 != NULL) { - rv = xbps_file_sha256_check(item->file, item->old.sha256); + rv = xbps_file_hash_check(XBPS_HASH_SHA256, 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 c5f6b793..c82807c9 100644 --- a/lib/util_hash.c +++ b/lib/util_hash.c @@ -37,6 +37,7 @@ #include +#include "xbps.h" #include "xbps_api_impl.h" #if OPENSSL_VERSION_NUMBER < 0x10100000L @@ -118,14 +119,35 @@ xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filelen) return true; } -bool -xbps_file_sha256_raw(unsigned char *dst, unsigned int dstlen, const char *file) { +static const EVP_MD* +algorithm2epv_md(xbps_hash_algorithm_t type) { + switch (type) { + case XBPS_HASH_SHA256: + return EVP_sha256(); + case XBPS_HASH_BLAKE2B256: + return EVP_blake2s256(); + } + return NULL; +} + +int +xbps_hash_size_raw(xbps_hash_algorithm_t type) { + return EVP_MD_size(algorithm2epv_md(type)); +} + +int +xbps_hash_size(xbps_hash_algorithm_t type) { + return EVP_MD_size(algorithm2epv_md(type)) * 2 + 1; +} + +bool +xbps_file_hash_raw(xbps_hash_algorithm_t type, unsigned char *dst, unsigned int dstlen, const char *file) { int fd; ssize_t len; char buf[65536]; EVP_MD_CTX *mdctx; - if ((int) dstlen < EVP_MD_size(EVP_sha256())) { + if ((int) dstlen < xbps_hash_size_raw(type)) { errno = ENOBUFS; return false; } @@ -136,7 +158,7 @@ xbps_file_sha256_raw(unsigned char *dst, unsigned int dstlen, const char *file) if((mdctx = EVP_MD_CTX_new()) == NULL) return false; - if(EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) + if(EVP_DigestInit_ex(mdctx, algorithm2epv_md(type), NULL) != 1) return false; while ((len = read(fd, buf, sizeof(buf))) > 0) @@ -154,7 +176,7 @@ xbps_file_sha256_raw(unsigned char *dst, unsigned int dstlen, const char *file) } bool -xbps_file_sha256(char *dst, size_t dstlen, const char *file) +xbps_file_hash(xbps_hash_algorithm_t type, char *dst, size_t dstlen, const char *file) { unsigned char digest[XBPS_SHA256_DIGEST_SIZE]; @@ -164,7 +186,7 @@ xbps_file_sha256(char *dst, size_t dstlen, const char *file) return false; } - if (!xbps_file_sha256_raw(digest, sizeof digest, file)) + if (!xbps_file_hash_raw(type, digest, sizeof digest, file)) return false; digest2string(digest, dst, XBPS_SHA256_DIGEST_SIZE); @@ -173,7 +195,7 @@ xbps_file_sha256(char *dst, size_t dstlen, const char *file) } static bool -sha256_digest_compare(const char *sha256, size_t shalen, +hash_digest_compare(const char *sha256, size_t shalen, const unsigned char *digest, size_t digestlen) { @@ -207,17 +229,17 @@ sha256_digest_compare(const char *sha256, size_t shalen, } int -xbps_file_sha256_check(const char *file, const char *sha256) +xbps_file_hash_check(xbps_hash_algorithm_t type, const char *file, const char *sha256) { unsigned char digest[XBPS_SHA256_DIGEST_SIZE]; assert(file != NULL); assert(sha256 != NULL); - if (!xbps_file_sha256_raw(digest, sizeof digest, file)) + if (!xbps_file_hash_raw(type, digest, sizeof digest, file)) return errno; - if (!sha256_digest_compare(sha256, strlen(sha256), digest, sizeof digest)) + if (!hash_digest_compare(sha256, strlen(sha256), digest, sizeof digest)) return ERANGE; return 0; @@ -278,10 +300,10 @@ xbps_file_hash_check_dictionary(struct xbps_handle *xhp, } if (strcmp(xhp->rootdir, "/") == 0) { - rv = xbps_file_sha256_check(file, sha256d); + rv = xbps_file_hash_check(XBPS_HASH_SHA256, file, sha256d); } else { buf = xbps_xasprintf("%s/%s", xhp->rootdir, file); - rv = xbps_file_sha256_check(buf, sha256d); + rv = xbps_file_hash_check(XBPS_HASH_SHA256, buf, sha256d); free(buf); } if (rv == 0) diff --git a/lib/verifysig.c b/lib/verifysig.c index b8b8f4c2..2638a30a 100644 --- a/lib/verifysig.c +++ b/lib/verifysig.c @@ -139,7 +139,7 @@ xbps_verify_file_signature(struct xbps_repo *repo, const char *fname) unsigned char digest[XBPS_SHA256_DIGEST_SIZE]; bool val = false; - if (!xbps_file_sha256_raw(digest, sizeof digest, fname)) { + if (!xbps_file_hash_raw(XBPS_HASH_SHA256, digest, sizeof digest, fname)) { xbps_dbg_printf("can't open file %s: %s\n", fname, strerror(errno)); return false; } From e6bb80e09ba6d17a2eceba7bd877257004cc3574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedel=20Sch=C3=B6n?= Date: Tue, 23 Jan 2024 20:07:40 +0100 Subject: [PATCH 3/6] remove TODO: blake2b-support --- TODO | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO b/TODO index eb95ee6e..3efb9cd0 100644 --- a/TODO +++ b/TODO @@ -18,7 +18,4 @@ xbps-fetch: - configurable libfetch timeout - configurable number of connection retries -xbps-digest: - - blake2b support - Issues listed at https://github.com/void-linux/xbps/issues From 165bb1d50df7816790174d77e67a0f569d1efde2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedel=20Sch=C3=B6n?= Date: Tue, 23 Jan 2024 20:14:05 +0100 Subject: [PATCH 4/6] include: add documentation --- include/xbps.h.in | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/include/xbps.h.in b/include/xbps.h.in index 1541fe4f..3c3077ae 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -1882,19 +1882,42 @@ char *xbps_xasprintf(const char *fmt, ...)__attribute__ ((format (printf, 1, 2)) */ bool xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filelen); +/** + * @enum xbps_hash_algorithm + * + * Enum describing which algorithm should be used to hash + * + * - XBPS_HASH_SHA256: use sha256 hashing + * - XBPS_HASH_BLAKE2B256: use blake2b (256bit) hashing + */ typedef enum xbps_hash_algorithm { XBPS_HASH_SHA256, XBPS_HASH_BLAKE2B256 } xbps_hash_algorithm_t; -int xbps_hash_size_raw(xbps_hash_algorithm_t type); +/** + * Represents the raw size of a digest (thus sha256 being 32bit) + * + * @param[in] algo Algorithm to describe + * + * @return Size in bytes + */ +int xbps_hash_size_raw(xbps_hash_algorithm_t algo); -int xbps_hash_size(xbps_hash_algorithm_t type); +/** + * Represents the hexstring-size including null-terminating byte of a digest (thus sha256 being 65bit) + * + * @param[in] algo Algorithm to describe + * + * @return Size in bytes + */ +int xbps_hash_size(xbps_hash_algorithm_t algo); /** - * Computes a sha256 hex digest into \a dst of size \a len + * Computes a hex digest into \a dst of size \a len * from file \a file. * + * @param[in] algo Hashing algorithm to use * @param[out] dst Destination buffer. * @param[in] len Size of \a dst must be at least XBPS_SHA256_LENGTH. * @param[in] file The file to read. @@ -1904,9 +1927,10 @@ int xbps_hash_size(xbps_hash_algorithm_t type); bool xbps_file_hash(xbps_hash_algorithm_t algo, char *dst, size_t len, const char *file); /** - * Computes a sha256 binary digest into \a dst of size \a len + * Computes a binary digest into \a dst of size \a len * from file \a file. * + * @param[in] algo Hashing algorithm to use * @param[out] dst Destination buffer. * @param[in] len Size of \a dst must be at least XBPS_SHA256_DIGEST_SIZE_LENGTH. * @param[in] file The file to read. @@ -1916,16 +1940,17 @@ bool xbps_file_hash(xbps_hash_algorithm_t algo, char *dst, size_t len, const cha bool xbps_file_hash_raw(xbps_hash_algorithm_t algo, unsigned char *dst, unsigned int len, const char *file); /** - * Compares the sha256 hash of the file \a file with the sha256 + * Compares the hash of the file \a file with the sha256 * string specified by \a sha256. * + * @param[in] algo Hashing algorithm to use * @param[in] file Path to a file. - * @param[in] sha256 SHA256 hash to compare. + * @param[in] digest hash to compare. * * @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(xbps_hash_algorithm_t algo, const char *file, const char *sha256); +int xbps_file_hash_check(xbps_hash_algorithm_t algo, const char *file, const char *digest); /** * Verifies the RSA signature \a sigfile against \a digest with the From bc893f4376d5746448c13f286528e20f158763fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedel=20Sch=C3=B6n?= Date: Tue, 23 Jan 2024 21:25:03 +0100 Subject: [PATCH 5/6] lib: add error-printing on openssl-error --- lib/util_hash.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/util_hash.c b/lib/util_hash.c index c82807c9..2141d631 100644 --- a/lib/util_hash.c +++ b/lib/util_hash.c @@ -23,6 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include @@ -36,6 +37,7 @@ #include #include +#include #include "xbps.h" #include "xbps_api_impl.h" @@ -147,6 +149,12 @@ xbps_file_hash_raw(xbps_hash_algorithm_t type, unsigned char *dst, unsigned int char buf[65536]; EVP_MD_CTX *mdctx; + // invalid type + if (algorithm2epv_md(type) == NULL) { + errno = EINVAL; + return false; + } + if ((int) dstlen < xbps_hash_size_raw(type)) { errno = ENOBUFS; return false; @@ -155,20 +163,28 @@ xbps_file_hash_raw(xbps_hash_algorithm_t type, unsigned char *dst, unsigned int if ((fd = open(file, O_RDONLY)) < 0) return false; - if((mdctx = EVP_MD_CTX_new()) == NULL) + if((mdctx = EVP_MD_CTX_new()) == NULL) { + xbps_error_printf("Unable to initial openssl: %s\n", ERR_error_string(ERR_get_error(), NULL)); return false; + } - if(EVP_DigestInit_ex(mdctx, algorithm2epv_md(type), NULL) != 1) + if(EVP_DigestInit_ex(mdctx, algorithm2epv_md(type), NULL) != 1) { + xbps_error_printf("Unable to initial algorithm: %s\n", ERR_error_string(ERR_get_error(), NULL)); return false; + } while ((len = read(fd, buf, sizeof(buf))) > 0) - if(EVP_DigestUpdate(mdctx, buf, len) != false) + if(EVP_DigestUpdate(mdctx, buf, len) != 1) { + xbps_error_printf("Unable to update digest: %s\n", ERR_error_string(ERR_get_error(), NULL)); return false; + } close(fd); - if(EVP_DigestFinal_ex(mdctx, dst, &dstlen) != 1) + if(EVP_DigestFinal_ex(mdctx, dst, &dstlen) != 1) { + xbps_error_printf("Unable to finalize digest: %s\n", ERR_error_string(ERR_get_error(), NULL)); return false; + } EVP_MD_CTX_free(mdctx); From e01f1f48998caf12dc11e0b92ce85a6c3c2a38cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedel=20Sch=C3=B6n?= Date: Tue, 23 Jan 2024 21:25:20 +0100 Subject: [PATCH 6/6] bin: add blake2b support --- bin/xbps-digest/main.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/bin/xbps-digest/main.c b/bin/xbps-digest/main.c index 229d4d86..1f7b4c70 100644 --- a/bin/xbps-digest/main.c +++ b/bin/xbps-digest/main.c @@ -41,7 +41,7 @@ usage(bool fail) "\n" "OPTIONS\n" " -h, --help Show usage\n" - " -m, --mode Selects the digest mode, sha256 (default)\n" + " -m, --mode Selects the digest mode, sha256 (default), blake2b\n" " -V, --version Show XBPS version\n" "\nNOTES\n" " If [file] not set, reads from stdin\n"); @@ -52,8 +52,10 @@ int main(int argc, char **argv) { int c; - char sha256[XBPS_SHA256_SIZE]; - const char *mode = NULL, *progname = argv[0]; + char* digest; + const char *modestr = NULL, *progname = argv[0]; + xbps_hash_algorithm_t mode = XBPS_HASH_SHA256; + int digest_size; const struct option longopts[] = { { "mode", required_argument, NULL, 'm' }, { "help", no_argument, NULL, 'h' }, @@ -67,7 +69,7 @@ main(int argc, char **argv) usage(false); /* NOTREACHED */ case 'm': - mode = optarg; + modestr = optarg; break; case 'V': printf("%s\n", XBPS_RELVER); @@ -82,27 +84,41 @@ main(int argc, char **argv) argc -= optind; argv += optind; - if (mode && strcmp(mode, "sha256")) { + if (modestr) { + if (strcmp(modestr, "sha256") == 0) { + mode = XBPS_HASH_SHA256; + } else if (strcmp(modestr, "blake2b") == 0) { + mode = XBPS_HASH_BLAKE2B256; + } else { + /* sha256 is the only supported mode currently */ + xbps_error_printf("%s: unsupported digest mode\n", progname); + exit(EXIT_FAILURE); + } + } + + digest_size = xbps_hash_size(mode); + if ((digest = malloc(digest_size)) == NULL) { /* sha256 is the only supported mode currently */ - xbps_error_printf("%s: unsupported digest mode\n", progname); + xbps_error_printf("%s: unable to allocate digest: %s\n", progname, strerror(errno)); exit(EXIT_FAILURE); } if (argc < 1) { - if (!xbps_file_hash(XBPS_HASH_SHA256, sha256, sizeof sha256, "/dev/stdin")) + if (!xbps_file_hash(mode, digest, digest_size, "/dev/stdin")) exit(EXIT_FAILURE); - - printf("%s\n", sha256); } else { for (int i = 0; i < argc; i++) { - if (!xbps_file_hash(XBPS_HASH_SHA256, sha256, sizeof sha256, argv[i])) { + if (!xbps_file_hash(mode, digest, digest_size, argv[i])) { xbps_error_printf( "%s: couldn't get hash for %s (%s)\n", progname, argv[i], strerror(errno)); exit(EXIT_FAILURE); } - printf("%s\n", sha256); } } + + printf("%s\n", digest); + + free(digest); exit(EXIT_SUCCESS); }