diff --git a/bin/xbps-rindex/defs.h b/bin/xbps-rindex/defs.h index 1545ed23..bf808d1f 100644 --- a/bin/xbps-rindex/defs.h +++ b/bin/xbps-rindex/defs.h @@ -67,21 +67,22 @@ #define _XBPS_RINDEX "xbps-rindex" /* From index-add.c */ -int index_add(struct xbps_handle *, int, int, char **, bool, const char *); +int index_add(struct xbps_handle *, int, int, char **, bool, const char *, const char *); /* From index-clean.c */ -int index_clean(struct xbps_handle *, const char *, bool, const char *); +int index_clean(struct xbps_handle *, const char *, bool, const char *, const char *); /* From remove-obsoletes.c */ int remove_obsoletes(struct xbps_handle *, const char *); /* From sign.c */ +int sign_buffer(const char *, unsigned int, const char *, unsigned char **, unsigned int *); int sign_repo(struct xbps_handle *, const char *, const char *, const char *, const char *); int sign_pkgs(struct xbps_handle *, int, int, char **, const char *, bool); /* From repoflush.c */ bool repodata_flush(struct xbps_handle *, const char *, const char *, - xbps_dictionary_t, xbps_dictionary_t, const char *); + xbps_dictionary_t, xbps_dictionary_t, const char *, const char *); #endif /* !_XBPS_RINDEX_DEFS_H_ */ diff --git a/bin/xbps-rindex/index-add.c b/bin/xbps-rindex/index-add.c index 95b249cf..0d4a5e63 100644 --- a/bin/xbps-rindex/index-add.c +++ b/bin/xbps-rindex/index-add.c @@ -57,7 +57,7 @@ set_build_date(const xbps_dictionary_t pkgd, time_t timestamp) static bool repodata_commit(struct xbps_handle *xhp, const char *repodir, xbps_dictionary_t idx, xbps_dictionary_t meta, xbps_dictionary_t stage, - const char *compression) + const char *compression, const char *privkey) { xbps_object_iterator_t iter; xbps_object_t keysym; @@ -189,7 +189,7 @@ repodata_commit(struct xbps_handle *xhp, const char *repodir, printf("stage: added `%s' (%s)\n", pkgver, arch); } xbps_object_iterator_release(iter); - rv = repodata_flush(xhp, repodir, "stagedata", stage, NULL, compression); + rv = repodata_flush(xhp, repodir, "stagedata", stage, NULL, compression, privkey); } else { char *stagefile; @@ -207,7 +207,7 @@ repodata_commit(struct xbps_handle *xhp, const char *repodir, stagefile = xbps_repo_path_with_name(xhp, repodir, "stagedata"); unlink(stagefile); free(stagefile); - rv = repodata_flush(xhp, repodir, "repodata", idx, meta, compression); + rv = repodata_flush(xhp, repodir, "repodata", idx, meta, compression, privkey); } xbps_object_release(usedshlibs); xbps_object_release(oldshlibs); @@ -215,7 +215,7 @@ repodata_commit(struct xbps_handle *xhp, const char *repodir, } int -index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force, const char *compression) +index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force, const char *compression, const char *privkey) { xbps_dictionary_t idx, idxmeta, idxstage, binpkgd, curpkgd; struct xbps_repo *repo = NULL, *stage = NULL; @@ -407,7 +407,7 @@ index_add(struct xbps_handle *xhp, int args, int argmax, char **argv, bool force /* * Generate repository data files. */ - if (!repodata_commit(xhp, repodir, idx, idxmeta, idxstage, compression)) { + if (!repodata_commit(xhp, repodir, idx, idxmeta, idxstage, compression, privkey)) { fprintf(stderr, "%s: failed to write repodata: %s\n", _XBPS_RINDEX, strerror(errno)); goto out; diff --git a/bin/xbps-rindex/index-clean.c b/bin/xbps-rindex/index-clean.c index 0160038c..0995527b 100644 --- a/bin/xbps-rindex/index-clean.c +++ b/bin/xbps-rindex/index-clean.c @@ -95,7 +95,7 @@ out: static int cleanup_repo(struct xbps_handle *xhp, const char *repodir, struct xbps_repo *repo, - const char *reponame, bool hashcheck, const char *compression) + const char *reponame, bool hashcheck, const char *compression, const char *privkey) { int rv = 0; xbps_array_t allkeys; @@ -117,7 +117,7 @@ cleanup_repo(struct xbps_handle *xhp, const char *repodir, struct xbps_repo *rep free(stagefile); } if (!xbps_dictionary_equals(dest, repo->idx)) { - if (!repodata_flush(xhp, repodir, reponame, dest, repo->idxmeta, compression)) { + if (!repodata_flush(xhp, repodir, reponame, dest, repo->idxmeta, compression, privkey)) { rv = errno; fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); @@ -136,7 +136,7 @@ cleanup_repo(struct xbps_handle *xhp, const char *repodir, struct xbps_repo *rep * binary package cannot be read (unavailable, not enough perms, etc). */ int -index_clean(struct xbps_handle *xhp, const char *repodir, const bool hashcheck, const char *compression) +index_clean(struct xbps_handle *xhp, const char *repodir, const bool hashcheck, const char *compression, const char *privkey) { struct xbps_repo *repo, *stage; char *rlockfname = NULL; @@ -168,11 +168,11 @@ index_clean(struct xbps_handle *xhp, const char *repodir, const bool hashcheck, } printf("Cleaning `%s' index, please wait...\n", repodir); - if ((rv = cleanup_repo(xhp, repodir, repo, "repodata", hashcheck, compression))) { + if ((rv = cleanup_repo(xhp, repodir, repo, "repodata", hashcheck, compression, privkey))) { goto out; } if (stage) { - cleanup_repo(xhp, repodir, stage, "stagedata", hashcheck, compression); + cleanup_repo(xhp, repodir, stage, "stagedata", hashcheck, compression, privkey); } out: diff --git a/bin/xbps-rindex/main.c b/bin/xbps-rindex/main.c index fab83425..624ae452 100644 --- a/bin/xbps-rindex/main.c +++ b/bin/xbps-rindex/main.c @@ -155,9 +155,9 @@ main(int argc, char **argv) } if (add_mode) - rv = index_add(&xh, optind, argc, argv, force, compression); + rv = index_add(&xh, optind, argc, argv, force, compression, privkey); else if (clean_mode) - rv = index_clean(&xh, argv[optind], hashcheck, compression); + rv = index_clean(&xh, argv[optind], hashcheck, compression, privkey); else if (rm_mode) rv = remove_obsoletes(&xh, argv[optind]); else if (sign_mode) diff --git a/bin/xbps-rindex/repoflush.c b/bin/xbps-rindex/repoflush.c index eb08bcfa..52110c7e 100644 --- a/bin/xbps-rindex/repoflush.c +++ b/bin/xbps-rindex/repoflush.c @@ -40,11 +40,13 @@ bool repodata_flush(struct xbps_handle *xhp, const char *repodir, const char *reponame, xbps_dictionary_t idx, xbps_dictionary_t meta, - const char *compression) + const char *compression, const char *privkey) { struct archive *ar; char *repofile, *tname, *buf; + unsigned char *sig = NULL; int rv, repofd = -1; + unsigned int siglen, buflen; mode_t mask; bool result; @@ -91,11 +93,30 @@ repodata_flush(struct xbps_handle *xhp, const char *repodir, buf = xbps_dictionary_externalize(idx); if (buf == NULL) return false; - rv = xbps_archive_append_buf(ar, buf, strlen(buf), + buflen = strlen(buf); + rv = xbps_archive_append_buf(ar, buf, buflen, XBPS_REPOIDX, 0644, "root", "root"); - free(buf); - if (rv != 0) + if (rv != 0) { + free(buf); return false; + } + if (meta != NULL) + { + rv = sign_buffer(buf, buflen, privkey, &sig, &siglen); + free(buf); + if (rv != 0) { + free(sig); + return false; + } + assert(sig); + rv = xbps_archive_append_buf(ar, sig, siglen, + XBPS_REPOIDX_SIG, 0644, "root", "root"); + if (rv != 0) { + free(sig); + return false; + } + free(sig); + } /* XBPS_REPOIDX_META */ if (meta == NULL) { diff --git a/bin/xbps-rindex/sign.c b/bin/xbps-rindex/sign.c index 4a714bb9..949dbe62 100644 --- a/bin/xbps-rindex/sign.c +++ b/bin/xbps-rindex/sign.c @@ -93,6 +93,32 @@ pubkey_from_privkey(RSA *rsa) return buf; } +static bool +rsa_sign_buffer(RSA *rsa, const char *buffer, unsigned int buflen, + unsigned char **sigret, unsigned int *siglen) +{ + unsigned char *sha256; + + sha256 = xbps_buffer_hash_raw(buffer, buflen); + if(!sha256) + return false; + + if ((*sigret = calloc(1, RSA_size(rsa) + 1)) == NULL) { + free(sha256); + return false; + } + + if (!RSA_sign(NID_sha1, sha256, SHA256_DIGEST_LENGTH, + *sigret, siglen, rsa)) { + free(sha256); + free(*sigret); + return false; + } + + free(sha256); + return true; +} + static bool rsa_sign_file(RSA *rsa, const char *file, unsigned char **sigret, unsigned int *siglen) @@ -150,6 +176,26 @@ ssl_init(void) SSL_library_init(); } +int +sign_buffer(const char *buffer, unsigned int buflen, const char *privkey, unsigned char **sig, unsigned int *sig_len) +{ + RSA *rsa = NULL; + int rv = 0; + + rsa = load_rsa_key(privkey); + if (!rsa_sign_buffer(rsa, buffer, buflen, sig, sig_len)) { + fprintf(stderr, "failed to sign buffer (%u bytes): %s\n", buflen, strerror(errno)); + rv = EINVAL; + } + + if (rsa) { + RSA_free(rsa); + rsa = NULL; + } + + return rv; +} + int sign_repo(struct xbps_handle *xhp, const char *repodir, const char *privkey, const char *signedby, const char *compression) @@ -231,7 +277,7 @@ sign_repo(struct xbps_handle *xhp, const char *repodir, _XBPS_RINDEX, strerror(errno)); goto out; } - flush_failed = repodata_flush(xhp, repodir, "repodata", repo->idx, meta, compression); + flush_failed = repodata_flush(xhp, repodir, "repodata", repo->idx, meta, compression, privkey); xbps_repo_unlock(rlockfd, rlockfname); if (!flush_failed) { fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); diff --git a/include/xbps.h.in b/include/xbps.h.in index 5adec1a6..46a5592f 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -116,6 +116,12 @@ */ #define XBPS_REPOIDX "index.plist" +/** + * @def XBPS_REPOIDX_SIG + * Filename for the signature of repository index property list. + */ +#define XBPS_REPOIDX_SIG "index.plist.sig" + /** * @def XBPS_REPOIDX_META * Filename for the repository index metadata property list. @@ -1843,6 +1849,18 @@ bool xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filele */ char *xbps_file_hash(const char *file); +/** + * Returns a raw byte buffer with the sha256 hash for the data specified + * in \a buffer of length \a len. + * + * @param[in] buffer Pointer to byte buffer. + * @param[in] len Length of data in buffer + * @return A pointer to a malloc(3)ed buffer, NULL otherwise and errno + * is set appropiately. The pointer should be free(3)d when it's no + * longer needed. + */ +unsigned char *xbps_buffer_hash_raw(const char *buffer, ssize_t len); + /** * Returns a raw byte buffer with the sha256 hash for the file specified * by \a file. diff --git a/lib/util_hash.c b/lib/util_hash.c index 985e9063..e57bee7c 100644 --- a/lib/util_hash.c +++ b/lib/util_hash.c @@ -108,6 +108,22 @@ xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filelen) return true; } +unsigned char * +xbps_buffer_hash_raw(const char *buffer, ssize_t len) +{ + unsigned char *digest; + SHA256_CTX sha256; + + digest = malloc(SHA256_DIGEST_LENGTH); + assert(digest); + + SHA256_Init(&sha256); + SHA256_Update(&sha256, buffer, len); + SHA256_Final(digest, &sha256); + + return digest; +} + unsigned char * xbps_file_hash_raw(const char *file) {