From 6f10adcd5931af4533602e07fb8042414abe3e58 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Mon, 27 Jul 2026 19:20:07 +0200 Subject: [PATCH] xar: Add support for SHA256 and SHA512 Extend the xar reader and writer to understand the SHA256 (header cksum_alg 3, 32 bytes, style "sha256") and SHA512 (cksum_alg 4, 64 bytes, style "sha512") checksum algorithms in addition to the existing SHA1 and MD5. These are the algorithm codes defined by the canonical xar format, so archives written with them interoperate with Apple's xar, pkgutil, and PackageKit. Both the TOC ("toc-checksum") and per-file ("checksum") algorithms are supported for writing. New algorithm handling is guarded by ARCHIVE_HAS_SHA256 / ARCHIVE_HAS_SHA512 so builds without those digests are unaffected. MAX_SUM_SIZE grows from 20 to 64 to hold a SHA512 digest. --- libarchive/archive_read_support_format_xar.c | 63 +++++++++++++++-- libarchive/archive_write_set_format_xar.c | 72 +++++++++++++++++++- libarchive/archive_write_set_options.3 | 14 ++-- libarchive/test/test_write_format_xar.c | 10 ++- 4 files changed, 147 insertions(+), 12 deletions(-) diff --git a/libarchive/archive_read_support_format_xar.c b/libarchive/archive_read_support_format_xar.c index cd61342ab..612b104f0 100644 --- a/libarchive/archive_read_support_format_xar.c +++ b/libarchive/archive_read_support_format_xar.c @@ -108,10 +108,14 @@ archive_read_support_format_xar(struct archive *_a) #define CKSUM_NONE 0 #define CKSUM_SHA1 1 #define CKSUM_MD5 2 +#define CKSUM_SHA256 3 +#define CKSUM_SHA512 4 #define MD5_SIZE 16 #define SHA1_SIZE 20 -#define MAX_SUM_SIZE 20 +#define SHA256_SIZE 32 +#define SHA512_SIZE 64 +#define MAX_SUM_SIZE 64 enum enctype { NONE, @@ -135,6 +139,12 @@ struct chksumwork { #ifdef ARCHIVE_HAS_SHA1 archive_sha1_ctx sha1ctx; #endif +#ifdef ARCHIVE_HAS_SHA256 + archive_sha256_ctx sha256ctx; +#endif +#ifdef ARCHIVE_HAS_SHA512 + archive_sha512_ctx sha512ctx; +#endif }; struct xattr { @@ -524,6 +534,8 @@ xar_bid(struct archive_read *a, int best_bid) case CKSUM_NONE: case CKSUM_SHA1: case CKSUM_MD5: + case CKSUM_SHA256: + case CKSUM_SHA512: bid += 32; break; default: @@ -1343,6 +1355,16 @@ _checksum_init(struct chksumwork *sumwrk, int sum_alg) case CKSUM_MD5: archive_md5_init(&(sumwrk->md5ctx)); break; +#ifdef ARCHIVE_HAS_SHA256 + case CKSUM_SHA256: + archive_sha256_init(&(sumwrk->sha256ctx)); + break; +#endif +#ifdef ARCHIVE_HAS_SHA512 + case CKSUM_SHA512: + archive_sha512_init(&(sumwrk->sha512ctx)); + break; +#endif } } @@ -1359,6 +1381,16 @@ _checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size) case CKSUM_MD5: archive_md5_update(&(sumwrk->md5ctx), buff, size); break; +#ifdef ARCHIVE_HAS_SHA256 + case CKSUM_SHA256: + archive_sha256_update(&(sumwrk->sha256ctx), buff, size); + break; +#endif +#ifdef ARCHIVE_HAS_SHA512 + case CKSUM_SHA512: + archive_sha512_update(&(sumwrk->sha512ctx), buff, size); + break; +#endif } } @@ -1383,6 +1415,22 @@ _checksum_final(struct chksumwork *sumwrk, const void *val, size_t len) memcmp(val, sum, MD5_SIZE) != 0) r = ARCHIVE_FAILED; break; +#ifdef ARCHIVE_HAS_SHA256 + case CKSUM_SHA256: + archive_sha256_final(&(sumwrk->sha256ctx), sum); + if (len != SHA256_SIZE || + memcmp(val, sum, SHA256_SIZE) != 0) + r = ARCHIVE_FAILED; + break; +#endif +#ifdef ARCHIVE_HAS_SHA512 + case CKSUM_SHA512: + archive_sha512_final(&(sumwrk->sha512ctx), sum); + if (len != SHA512_SIZE || + memcmp(val, sum, SHA512_SIZE) != 0) + r = ARCHIVE_FAILED; + break; +#endif } return (r); } @@ -1884,9 +1932,16 @@ getsumalgorithm(struct xmlattr_list *list) const char *v = attr->value; if ((v[0] == 'S' || v[0] == 's') && (v[1] == 'H' || v[1] == 'h') && - (v[2] == 'A' || v[2] == 'a') && - v[3] == '1' && v[4] == '\0') - alg = CKSUM_SHA1; + (v[2] == 'A' || v[2] == 'a')) { + if (v[3] == '1' && v[4] == '\0') + alg = CKSUM_SHA1; + else if (v[3] == '2' && v[4] == '5' && + v[5] == '6' && v[6] == '\0') + alg = CKSUM_SHA256; + else if (v[3] == '5' && v[4] == '1' && + v[5] == '2' && v[6] == '\0') + alg = CKSUM_SHA512; + } if ((v[0] == 'M' || v[0] == 'm') && (v[1] == 'D' || v[1] == 'd') && v[2] == '5' && v[3] == '\0') diff --git a/libarchive/archive_write_set_format_xar.c b/libarchive/archive_write_set_format_xar.c index c3e444f7e..005869379 100644 --- a/libarchive/archive_write_set_format_xar.c +++ b/libarchive/archive_write_set_format_xar.c @@ -129,14 +129,20 @@ static int xml_writer_destroy(struct xml_writer *ctx); enum sumalg { CKSUM_NONE = 0, CKSUM_SHA1 = 1, - CKSUM_MD5 = 2 + CKSUM_MD5 = 2, + CKSUM_SHA256 = 3, + CKSUM_SHA512 = 4 }; #define MD5_SIZE 16 #define SHA1_SIZE 20 -#define MAX_SUM_SIZE 20 +#define SHA256_SIZE 32 +#define SHA512_SIZE 64 +#define MAX_SUM_SIZE 64 #define MD5_NAME "md5" #define SHA1_NAME "sha1" +#define SHA256_NAME "sha256" +#define SHA512_NAME "sha512" enum enctype { NONE, @@ -154,6 +160,12 @@ struct chksumwork { #ifdef ARCHIVE_HAS_SHA1 archive_sha1_ctx sha1ctx; #endif +#ifdef ARCHIVE_HAS_SHA256 + archive_sha256_ctx sha256ctx; +#endif +#ifdef ARCHIVE_HAS_SHA512 + archive_sha512_ctx sha512ctx; +#endif }; enum la_zaction { @@ -445,6 +457,14 @@ xar_options(struct archive_write *a, const char *key, const char *value) xar->opt_sumalg = CKSUM_SHA1; else if (strcmp(value, "md5") == 0) xar->opt_sumalg = CKSUM_MD5; +#ifdef ARCHIVE_HAS_SHA256 + else if (strcmp(value, "sha256") == 0) + xar->opt_sumalg = CKSUM_SHA256; +#endif +#ifdef ARCHIVE_HAS_SHA512 + else if (strcmp(value, "sha512") == 0) + xar->opt_sumalg = CKSUM_SHA512; +#endif else { archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, @@ -520,6 +540,14 @@ xar_options(struct archive_write *a, const char *key, const char *value) xar->opt_toc_sumalg = CKSUM_SHA1; else if (strcmp(value, "md5") == 0) xar->opt_toc_sumalg = CKSUM_MD5; +#ifdef ARCHIVE_HAS_SHA256 + else if (strcmp(value, "sha256") == 0) + xar->opt_toc_sumalg = CKSUM_SHA256; +#endif +#ifdef ARCHIVE_HAS_SHA512 + else if (strcmp(value, "sha512") == 0) + xar->opt_toc_sumalg = CKSUM_SHA512; +#endif else { archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, @@ -2649,6 +2677,16 @@ checksum_init(struct chksumwork *sumwrk, enum sumalg sum_alg) case CKSUM_MD5: archive_md5_init(&(sumwrk->md5ctx)); break; +#ifdef ARCHIVE_HAS_SHA256 + case CKSUM_SHA256: + archive_sha256_init(&(sumwrk->sha256ctx)); + break; +#endif +#ifdef ARCHIVE_HAS_SHA512 + case CKSUM_SHA512: + archive_sha512_init(&(sumwrk->sha512ctx)); + break; +#endif } } @@ -2665,6 +2703,16 @@ checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size) case CKSUM_MD5: archive_md5_update(&(sumwrk->md5ctx), buff, size); break; +#ifdef ARCHIVE_HAS_SHA256 + case CKSUM_SHA256: + archive_sha256_update(&(sumwrk->sha256ctx), buff, size); + break; +#endif +#ifdef ARCHIVE_HAS_SHA512 + case CKSUM_SHA512: + archive_sha512_update(&(sumwrk->sha512ctx), buff, size); + break; +#endif } } @@ -2684,6 +2732,18 @@ checksum_final(struct chksumwork *sumwrk, struct chksumval *sumval) archive_md5_final(&(sumwrk->md5ctx), sumval->val); sumval->len = MD5_SIZE; break; +#ifdef ARCHIVE_HAS_SHA256 + case CKSUM_SHA256: + archive_sha256_final(&(sumwrk->sha256ctx), sumval->val); + sumval->len = SHA256_SIZE; + break; +#endif +#ifdef ARCHIVE_HAS_SHA512 + case CKSUM_SHA512: + archive_sha512_final(&(sumwrk->sha512ctx), sumval->val); + sumval->len = SHA512_SIZE; + break; +#endif } sumval->alg = sumwrk->alg; } @@ -3311,6 +3371,10 @@ getalgsize(enum sumalg sumalg) return (SHA1_SIZE); case CKSUM_MD5: return (MD5_SIZE); + case CKSUM_SHA256: + return (SHA256_SIZE); + case CKSUM_SHA512: + return (SHA512_SIZE); } } @@ -3325,6 +3389,10 @@ getalgname(enum sumalg sumalg) return (SHA1_NAME); case CKSUM_MD5: return (MD5_NAME); + case CKSUM_SHA256: + return (SHA256_NAME); + case CKSUM_SHA512: + return (SHA512_NAME); } } diff --git a/libarchive/archive_write_set_options.3 b/libarchive/archive_write_set_options.3 index 9fc24e699..e03b51757 100644 --- a/libarchive/archive_write_set_options.3 +++ b/libarchive/archive_write_set_options.3 @@ -622,9 +622,11 @@ as file checksum method. Supported values are .Dq none , .Dq md5 , -and .Dq sha1 -.Pq default . +.Pq default , +.Dq sha256 , +and +.Dq sha512 . .It Cm compression Ns = Ns Ar type Use .Ar type @@ -645,10 +647,12 @@ Use as table of contents checksum method. Supported values are .Dq none , -.Dq md5 -and +.Dq md5 , .Dq sha1 -.Pq default . +.Pq default , +.Dq sha256 , +and +.Dq sha512 . .El .It Format zip .Bl -tag -compact -width indent diff --git a/libarchive/test/test_write_format_xar.c b/libarchive/test/test_write_format_xar.c index bb24fffc3..2f185898f 100644 --- a/libarchive/test/test_write_format_xar.c +++ b/libarchive/test/test_write_format_xar.c @@ -34,7 +34,7 @@ static void test_xar(const char *option) { char buff2[64]; - size_t buffsize = 1500; + size_t buffsize = 4096; char *buff; struct archive_entry *ae; struct archive *a; @@ -325,6 +325,10 @@ DEFINE_TEST(test_write_format_xar) test_xar("toc-checksum=sha1"); /* Specify TOC checksum type to md5. */ test_xar("toc-checksum=md5"); + /* Specify TOC checksum type to sha256. */ + test_xar("toc-checksum=sha256"); + /* Specify TOC checksum type to sha512. */ + test_xar("toc-checksum=sha512"); /* Disable file checksum. */ test_xar("!checksum"); @@ -333,6 +337,10 @@ DEFINE_TEST(test_write_format_xar) test_xar("checksum=sha1"); /* Specify file checksum type to md5. */ test_xar("checksum=md5"); + /* Specify file checksum type to sha256. */ + test_xar("checksum=sha256"); + /* Specify file checksum type to sha512. */ + test_xar("checksum=sha512"); /* Disable compression. */ test_xar("!compression"); -- 2.47.3