From d08e76a386b37cc2c57779e80dd22075d18a8772 Mon Sep 17 00:00:00 2001 From: Juan RP Date: Thu, 30 Jan 2014 13:07:34 +0100 Subject: [PATCH] Keep repo metadata if possible when updating repodata (xbps-rindex -a/-c). API/ABI incompat changes, you've been warned. --- COPYING | 2 +- NEWS | 14 +++++++++ bin/xbps-query/list.c | 20 +++++++++--- bin/xbps-rindex/index-add.c | 8 +++-- bin/xbps-rindex/index-clean.c | 5 +-- bin/xbps-rindex/sign.c | 39 ++++++++---------------- include/xbps.h.in | 32 +++++--------------- lib/repo.c | 57 +++++++++++++++++++---------------- lib/verifysig.c | 15 ++++++--- 9 files changed, 99 insertions(+), 93 deletions(-) diff --git a/COPYING b/COPYING index 4d190250..92ec1186 100644 --- a/COPYING +++ b/COPYING @@ -1,7 +1,7 @@ Almost all code in XBPS uses the following license (some exceptions are shown below): -/* Copyright (c) 2008-2012 Juan Romero Pardines. +/* Copyright (c) 2008-2014 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/NEWS b/NEWS index 69efc4c4..bc184038 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,19 @@ xbps-0.31 (??): + * Removed 0.27 compat from repodata. + + * If a repository has been signed previously respect its settings + in repodata (unless there were new changes). This allows us to + accomplish the following: + + $ xbps-rindex repo/*.xbps + $ xbps-rindex --sign ... repo + $ xbps-rindex repo/new-pkg.xbps + + ... and repository is still signed after updating repodata. + + API/ABI incompatible changes, you've been warned :-) + * xbps-rindex(8): -c [clean] mode now is fully multithread safe. * Fixed a double free while downloading binpkgs from remote repositories diff --git a/bin/xbps-query/list.c b/bin/xbps-query/list.c index 1278fdb8..3efd0cc2 100644 --- a/bin/xbps-query/list.c +++ b/bin/xbps-query/list.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2008-2013 Juan Romero Pardines. + * Copyright (c) 2008-2014 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -156,15 +156,25 @@ list_pkgs_pkgdb(struct xbps_handle *xhp) static int repo_list_uri_cb(struct xbps_repo *repo, void *arg _unused, bool *done _unused) { + const char *signedby, *hexfp; + uint16_t pubkeysize; + printf("%5zd %s", repo->idx ? (ssize_t)xbps_dictionary_count(repo->idx) : -1, repo->uri); printf(" (RSA %s)\n", repo->is_signed ? "signed" : "unsigned"); if (repo->xhp->flags & XBPS_FLAG_VERBOSE) { - if (repo->signedby) - printf(" Signed-by: %s\n", repo->signedby); - if (repo->hexfp) - printf(" %u %s\n", repo->pubkey_size, repo->hexfp); + xbps_data_t pubkey; + + xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &signedby); + xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &pubkeysize); + pubkey = xbps_dictionary_get(repo->idxmeta, "public-key"); + hexfp = xbps_pubkey2fp(repo->xhp, pubkey); + + if (signedby) + printf(" Signed-by: %s\n", signedby); + if (pubkeysize && hexfp) + printf(" %u %s\n", pubkeysize, hexfp); } return 0; } diff --git a/bin/xbps-rindex/index-add.c b/bin/xbps-rindex/index-add.c index bb1f8f1d..0325e4f7 100644 --- a/bin/xbps-rindex/index-add.c +++ b/bin/xbps-rindex/index-add.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012-2013 Juan Romero Pardines. + * Copyright (c) 2012-2014 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,7 +41,7 @@ int index_add(struct xbps_handle *xhp, int argc, char **argv, bool force) { xbps_array_t array, pkg_files, pkg_links, pkg_cffiles; - xbps_dictionary_t idx, idxfiles, binpkgd, pkg_filesd, curpkgd; + xbps_dictionary_t idx, idxmeta, idxfiles, binpkgd, pkg_filesd, curpkgd; xbps_object_t obj, fileobj; struct xbps_repo *repo; struct stat st; @@ -62,10 +62,12 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force) if (repo && repo->idx) { xbps_repo_open_idxfiles(repo); idx = xbps_dictionary_copy(repo->idx); + idxmeta = xbps_dictionary_copy(repo->idxmeta); idxfiles = xbps_dictionary_copy(repo->idxfiles); xbps_repo_close(repo); } else { idx = xbps_dictionary_create(); + idxmeta = NULL; idxfiles = xbps_dictionary_create(); } @@ -241,7 +243,7 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force) * Generate repository data files. */ if (flush) { - if (!repodata_flush(xhp, repodir, idx, idxfiles, NULL)) { + if (!repodata_flush(xhp, repodir, idx, idxfiles, idxmeta)) { fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); return -1; } diff --git a/bin/xbps-rindex/index-clean.c b/bin/xbps-rindex/index-clean.c index 72fd4c53..ecc86dca 100644 --- a/bin/xbps-rindex/index-clean.c +++ b/bin/xbps-rindex/index-clean.c @@ -121,7 +121,7 @@ index_clean(struct xbps_handle *xhp, const char *repodir) struct xbps_repo *repo; struct cbdata cbd; xbps_array_t allkeys; - xbps_dictionary_t idx, idxfiles; + xbps_dictionary_t idx, idxmeta, idxfiles; char *keyname, *pkgname; int rv = 0; bool flush = false; @@ -135,6 +135,7 @@ index_clean(struct xbps_handle *xhp, const char *repodir) } xbps_repo_open_idxfiles(repo); idx = xbps_dictionary_copy(repo->idx); + idxmeta = xbps_dictionary_copy(repo->idxmeta); idxfiles = xbps_dictionary_copy(repo->idxfiles); xbps_repo_close(repo); if (idx == NULL || idxfiles == NULL) { @@ -185,7 +186,7 @@ index_clean(struct xbps_handle *xhp, const char *repodir) xbps_object_release(allkeys); if (flush) { - if (!repodata_flush(xhp, repodir, idx, idxfiles, NULL)) { + if (!repodata_flush(xhp, repodir, idx, idxfiles, idxmeta)) { fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); return -1; diff --git a/bin/xbps-rindex/sign.c b/bin/xbps-rindex/sign.c index d1ad3e47..d86613a3 100644 --- a/bin/xbps-rindex/sign.c +++ b/bin/xbps-rindex/sign.c @@ -119,14 +119,14 @@ sign_repo(struct xbps_handle *xhp, const char *repodir, struct stat st; struct xbps_repo *repo; xbps_dictionary_t pkgd, meta = NULL; - xbps_data_t data = NULL; + xbps_data_t data = NULL, rpubkey = NULL; xbps_object_iterator_t iter = NULL; xbps_object_t obj; RSA *rsa = NULL; unsigned char *sig; unsigned int siglen; - uint16_t pubkeysize; - const char *arch, *pkgver; + uint16_t rpubkeysize, pubkeysize; + const char *arch, *pkgver, *rsignedby; char *binpkg, *binpkg_sig, *buf, *defprivkey; int binpkg_fd, binpkg_sig_fd, rv = 0; bool flush = false; @@ -244,7 +244,7 @@ sign_repo(struct xbps_handle *xhp, const char *repodir, } xbps_object_iterator_release(iter); /* - * Check if repository meta contains changes compared to its + * Check if repository index-meta contains changes compared to its * current state. */ if ((buf = pubkey_from_privkey(rsa)) == NULL) { @@ -254,15 +254,19 @@ sign_repo(struct xbps_handle *xhp, const char *repodir, meta = xbps_dictionary_create(); data = xbps_data_create_data(buf, strlen(buf)); - if (!xbps_data_equals(repo->pubkey, data)) + rpubkey = xbps_dictionary_get(repo->idxmeta, "public-key"); + if (!xbps_data_equals(rpubkey, data)) flush = true; free(buf); + pubkeysize = RSA_size(rsa) * 8; - if (repo->pubkey_size != pubkeysize) + xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &rpubkeysize); + if (rpubkeysize != pubkeysize) flush = true; - if (repo->signedby == NULL || strcmp(repo->signedby, signedby)) + xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signedby", &rsignedby); + if (rsignedby == NULL || strcmp(rsignedby, signedby)) flush = true; if (!flush) @@ -273,22 +277,7 @@ sign_repo(struct xbps_handle *xhp, const char *repodir, xbps_dictionary_set_cstring_nocopy(meta, "signature-by", signedby); xbps_dictionary_set_cstring_nocopy(meta, "signature-type", "rsa"); xbps_object_release(data); - /* - * Compatibility with 0.27. - */ - if ((buf = xbps_dictionary_externalize(repo->idx)) == NULL) { - rv = errno; - fprintf(stderr, "failed to externalize repository index: %s\n", strerror(errno)); - goto out; - } - if (!rsa_sign_buf(rsa, buf, strlen(buf), &sig, &siglen)) { - rv = errno; - fprintf(stderr, "failed to create repository index signature: %s\n", strerror(errno)); - goto out; - } - data = xbps_data_create_data_nocopy(sig, siglen); - xbps_dictionary_set(meta, "signature", data); - free(buf); + data = NULL; if (!repodata_flush(xhp, repodir, repo->idx, repo->idxfiles, meta)) { fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); @@ -304,10 +293,6 @@ out: RSA_free(rsa); rsa = NULL; } - if (data) - xbps_object_release(data); - if (meta) - xbps_object_release(meta); if (repo) xbps_repo_close(repo); diff --git a/include/xbps.h.in b/include/xbps.h.in index 92ec18c9..090fccd5 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -50,7 +50,7 @@ * * This header documents the full API for the XBPS Library. */ -#define XBPS_API_VERSION "20131224" +#define XBPS_API_VERSION "20140130" #ifndef XBPS_VERSION #define XBPS_VERSION "UNSET" @@ -1123,36 +1123,18 @@ struct xbps_repo { * Proplib dictionary associated with the repository index. */ xbps_dictionary_t idx; + /** + * @var idxmeta + * + * Proplib dictionary associated with the repository index-meta. + */ + xbps_dictionary_t idxmeta; /** * @var idxfiles * * Proplib dictionary associated with the repository index-files. */ xbps_dictionary_t idxfiles; - /** - * @var pubkey - * - * RSA public key associated with this repository in a prop_data object. - */ - xbps_data_t pubkey; - /** - * @var hexfp - * - * OpenSSH fingerprint in hexadecimal of the RSA public key. - */ - char *hexfp; - /** - * @var signedby; - * - * The signee of the RSA signature associated with this repository (string). - */ - const char *signedby; - /** - * @var pubkey_size; - * - * Size in bits of the RSA public key associacted with this repository. - */ - uint16_t pubkey_size; /** * @var uri * diff --git a/lib/repo.c b/lib/repo.c index d3165d2a..8cfdbc2c 100644 --- a/lib/repo.c +++ b/lib/repo.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012-2013 Juan Romero Pardines. + * Copyright (c) 2012-2014 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -106,7 +106,6 @@ repo_get_dict(struct xbps_repo *repo) struct xbps_repo * xbps_repo_open(struct xbps_handle *xhp, const char *url) { - xbps_dictionary_t meta; struct xbps_repo *repo; struct stat st; const char *arch; @@ -165,15 +164,9 @@ xbps_repo_open(struct xbps_handle *xhp, const char *url) repo->ar = NULL; goto out; } - if ((meta = repo_get_dict(repo))) { - xbps_dictionary_get_cstring_nocopy(meta, "signature-by", &repo->signedby); - xbps_dictionary_get_uint16(meta, "public-key-size", &repo->pubkey_size); - repo->pubkey = xbps_dictionary_get(meta, "public-key"); - if (repo->pubkey) { - repo->is_signed = true; - repo->hexfp = xbps_pubkey2fp(repo->xhp, repo->pubkey); - } - } + repo->idxmeta = repo_get_dict(repo); + if (repo->idxmeta != NULL) + repo->is_signed = true; out: free(repofile); @@ -199,12 +192,14 @@ xbps_repo_close(struct xbps_repo *repo) xbps_object_release(repo->idx); repo->idx = NULL; } + if (repo->idxmeta != NULL) { + xbps_object_release(repo->idxmeta); + repo->idxmeta = NULL; + } if (repo->idxfiles != NULL) { xbps_object_release(repo->idxfiles); repo->idxfiles = NULL; } - if (repo->hexfp != NULL) - free(repo->hexfp); } xbps_dictionary_t @@ -417,6 +412,9 @@ int xbps_repo_key_import(struct xbps_repo *repo) { xbps_dictionary_t repokeyd = NULL; + xbps_data_t pubkey = NULL; + uint16_t pubkey_size = 0; + const char *hexfp = NULL, *signedby = NULL; char *p, *dbkeyd, *rkeyfile = NULL; int import, rv = 0; @@ -424,27 +422,34 @@ xbps_repo_key_import(struct xbps_repo *repo) /* * If repository does not have required metadata plist, ignore it. */ - if (repo->pubkey == NULL) { + if (!xbps_dictionary_count(repo->idxmeta)) { xbps_dbg_printf(repo->xhp, "[repo] `%s' unsigned repository!\n", repo->uri); return 0; } /* - * Check the repository provides a working public-key data object. + * Check for required objects in index-meta: + * - signature-by (string) + * - public-key (data) + * - public-key-size (number) */ - repo->is_signed = true; - if (repo->hexfp == NULL) { + xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &signedby); + xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &pubkey_size); + pubkey = xbps_dictionary_get(repo->idxmeta, "public-key"); + + if (signedby == NULL || pubkey_size == 0 || + xbps_object_type(pubkey) != XBPS_TYPE_DATA) { xbps_dbg_printf(repo->xhp, - "[repo] `%s': invalid hex fingerprint: %s\n", - repo->uri, strerror(errno)); + "[repo] `%s': incomplete signed repository " + "(missing objs)\n", repo->uri); rv = EINVAL; goto out; } + hexfp = xbps_pubkey2fp(repo->xhp, pubkey); /* * Check if the public key is alredy stored. */ - rkeyfile = xbps_xasprintf("%s/keys/%s.plist", - repo->xhp->metadir, repo->hexfp); + rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp); repokeyd = xbps_dictionary_internalize_from_zfile(rkeyfile); if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) { xbps_dbg_printf(repo->xhp, @@ -457,8 +462,8 @@ xbps_repo_key_import(struct xbps_repo *repo) * to the client. */ import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, 0, - repo->hexfp, "`%s' repository has been RSA signed by \"%s\"", - repo->uri, repo->signedby); + hexfp, "`%s' repository has been RSA signed by \"%s\"", + repo->uri, signedby); if (import <= 0) { rv = EAGAIN; goto out; @@ -482,9 +487,9 @@ xbps_repo_key_import(struct xbps_repo *repo) free(p); repokeyd = xbps_dictionary_create(); - xbps_dictionary_set(repokeyd, "public-key", repo->pubkey); - xbps_dictionary_set_uint16(repokeyd, "public-key-size", repo->pubkey_size); - xbps_dictionary_set_cstring_nocopy(repokeyd, "signature-by", repo->signedby); + xbps_dictionary_set(repokeyd, "public-key", pubkey); + xbps_dictionary_set_uint16(repokeyd, "public-key-size", pubkey_size); + xbps_dictionary_set_cstring_nocopy(repokeyd, "signature-by", signedby); if (!xbps_dictionary_externalize_to_zfile(repokeyd, rkeyfile)) { rv = errno; diff --git a/lib/verifysig.c b/lib/verifysig.c index 2ac262e7..5e02254e 100644 --- a/lib/verifysig.c +++ b/lib/verifysig.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2013 Juan Romero Pardines. + * Copyright (c) 2013-2014 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -82,18 +82,25 @@ xbps_verify_file_signature(struct xbps_repo *repo, const char *fname) xbps_dictionary_t repokeyd = NULL; xbps_data_t pubkey; struct stat st, sig_st; + const char *hexfp = NULL; unsigned char *buf = NULL, *sig_buf = NULL; char *rkeyfile = NULL, *sig = NULL; int fd = -1, sig_fd = -1; bool val = false; - if (!repo->hexfp) + if (!xbps_dictionary_count(repo->idxmeta)) { + xbps_dbg_printf(repo->xhp, "%s: unsigned repository\n", repo->uri); return false; + } + xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "hexfp", &hexfp); + if (hexfp == NULL) { + xbps_dbg_printf(repo->xhp, "%s: incomplete signed repo, missing hexfp obj\n", repo->uri); + return false; + } /* * Prepare repository RSA public key to verify fname signature. */ - rkeyfile = xbps_xasprintf("%s/keys/%s.plist", - repo->xhp->metadir, repo->hexfp); + rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp); repokeyd = xbps_dictionary_internalize_from_zfile(rkeyfile); if (xbps_object_type(repokeyd) != XBPS_TYPE_DICTIONARY) { xbps_dbg_printf(repo->xhp, "cannot read rkey data at %s: %s\n",