diff --git a/NEWS b/NEWS index 409dc364..6fdb9653 100644 --- a/NEWS +++ b/NEWS @@ -13,17 +13,15 @@ xbps-0.27 (???): * xbps-rindex(8): added -v --verbose option. - * xbps-rkeys(8): new utility to manage RSA public keys from remote signed repositories. - * Support for RSA signed repositories. A repository can be signed with your preferred RSA key (any ssh key works) as follows: $ xbps-rindex --sign --signedby "foobar " --privkey /priv/key /path/to/repo Public keys must be imported before using a remote signed repository thru - the xbps-rkeys(8) utility: + the xbps-install(8) utility: - $ xbps-rkeys -i + $ xbps-install -S Once the public key has been imported it's not expected to change, hence if the repository index has been modified or signed with another key, it will be ignored. diff --git a/bin/Makefile b/bin/Makefile index 4e65cb1b..e3a1ea42 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -9,6 +9,5 @@ SUBDIRS += xbps-reconfigure SUBDIRS += xbps-remove SUBDIRS += xbps-rindex SUBDIRS += xbps-uhelper -SUBDIRS += xbps-rkeys include ../mk/subdir.mk diff --git a/bin/xbps-create/xbps-create.8 b/bin/xbps-create/xbps-create.8 index 4cef7f17..589f0a9c 100644 --- a/bin/xbps-create/xbps-create.8 +++ b/bin/xbps-create/xbps-create.8 @@ -81,8 +81,7 @@ A list of required shared libraries, separated by a single blank. Example: .Xr xbps-query 8 , .Xr xbps-reconfigure 8 , .Xr xbps-remove 8 , -.Xr xbps-rindex 8 , -.Xr xbps-rkeys 8 +.Xr xbps-rindex 8 .Sh AUTHORS .An Juan Romero Pardines .Sh BUGS diff --git a/bin/xbps-install/main.c b/bin/xbps-install/main.c index 8179d11b..1b20687a 100644 --- a/bin/xbps-install/main.c +++ b/bin/xbps-install/main.c @@ -76,6 +76,18 @@ unpack_progress_cb(struct xbps_unpack_cb_data *xpd, void *cbdata _unused) xpd->entry_size); } +static int +repo_import_key_cb(struct xbps_repo *repo, void *arg _unused, bool *done _unused) +{ + int rv; + + if ((rv = xbps_repo_key_import(repo)) != 0) + fprintf(stderr, "Failed to import pubkey from %s: %s\n", + repo->uri, strerror(rv)); + + return rv; +} + int main(int argc, char **argv) { @@ -190,10 +202,13 @@ main(int argc, char **argv) maxcols = get_maxcols(); - /* Sync remote repository data by default */ + /* Sync remote repository data and import keys from remote repos */ if (sync && !drun) { if ((rv = xbps_rpool_sync(&xh, NULL)) != 0) exit(rv); + rv = xbps_rpool_foreach(&xh, repo_import_key_cb, NULL); + if (rv != 0) + exit(rv); } if (sync && !update && (argc == optind)) diff --git a/bin/xbps-install/state_cb.c b/bin/xbps-install/state_cb.c index 58d8d8ff..34f6b9ad 100644 --- a/bin/xbps-install/state_cb.c +++ b/bin/xbps-install/state_cb.c @@ -48,10 +48,10 @@ state_cb(struct xbps_state_cb_data *xscd, void *cbdata _unused) switch (xscd->state) { /* notifications */ case XBPS_STATE_REPO_SIGVERIFIED: - printf("[*] RSA signature verified correctly\n"); + printf("[*] %s: RSA signature verified\n", xscd->arg); break; case XBPS_STATE_REPO_SIGUNVERIFIED: - printf("[*] RSA signature UNVERIFIED! ignoring...\n"); + printf("[*] %s: RSA signature invalid! ignoring...\n", xscd->arg); break; case XBPS_STATE_TRANS_DOWNLOAD: printf("\n[*] Downloading binary packages\n"); @@ -130,6 +130,11 @@ state_cb(struct xbps_state_cb_data *xscd, void *cbdata _unused) "(rootdir: %s).", xscd->arg, xscd->xhp->rootdir); break; + case XBPS_STATE_REPO_KEY_IMPORT: + printf("%s\n", xscd->desc); + printf("Fingerprint: %s\n", xscd->arg); + rv = yesno("Do you want to import this public key?"); + break; /* errors */ case XBPS_STATE_UNPACK_FAIL: case XBPS_STATE_UPDATE_FAIL: diff --git a/bin/xbps-install/xbps-install.8 b/bin/xbps-install/xbps-install.8 index a4876c1c..d5e4093f 100644 --- a/bin/xbps-install/xbps-install.8 +++ b/bin/xbps-install/xbps-install.8 @@ -110,8 +110,7 @@ Default cache directory to store downloaded binary packages. .Xr xbps-query 8 , .Xr xbps-reconfigure 8 , .Xr xbps-remove 8 , -.Xr xbps-rindex 8 , -.Xr xbps-rkeys 8 +.Xr xbps-rindex 8 .Sh AUTHORS .An Juan Romero Pardines .Sh BUGS diff --git a/bin/xbps-pkgdb/xbps-pkgdb.8 b/bin/xbps-pkgdb/xbps-pkgdb.8 index f52844b0..67e6e680 100644 --- a/bin/xbps-pkgdb/xbps-pkgdb.8 +++ b/bin/xbps-pkgdb/xbps-pkgdb.8 @@ -81,8 +81,7 @@ Default cache directory to store downloaded binary packages. .Xr xbps-query 8 , .Xr xbps-reconfigure 8 , .Xr xbps-remove 8 , -.Xr xbps-rindex 8 , -.Xr xbps-rkeys 8 +.Xr xbps-rindex 8 .Sh AUTHORS .An Juan Romero Pardines .Sh BUGS diff --git a/bin/xbps-query/list.c b/bin/xbps-query/list.c index ad83cddf..cba4485f 100644 --- a/bin/xbps-query/list.c +++ b/bin/xbps-query/list.c @@ -160,11 +160,16 @@ repo_list_uri_cb(struct xbps_repo *repo, void *arg _unused, bool *done _unused) repo->idx ? (ssize_t)xbps_dictionary_count(repo->idx) : -1, repo->uri); if (repo->is_remote) { - printf(" (RSA %s, %s)", + printf(" (RSA %s, %s)\n", repo->is_signed ? "signed" : "unsigned", repo->is_verified ? "verified" : "unverified"); + if (repo->xhp->flags & XBPS_FLAG_VERBOSE) { + printf(" Signed-by: %s\n", repo->signedby); + printf(" %u %s\n", repo->pubkey_size, repo->hexfp); + } + } else { + printf("\n"); } - printf("\n"); return 0; } diff --git a/bin/xbps-query/xbps-query.8 b/bin/xbps-query/xbps-query.8 index eff5d243..17213e23 100644 --- a/bin/xbps-query/xbps-query.8 +++ b/bin/xbps-query/xbps-query.8 @@ -175,8 +175,7 @@ Default cache directory to store downloaded binary packages. .Xr xbps-pkgdb 8 , .Xr xbps-reconfigure 8 , .Xr xbps-remove 8 , -.Xr xbps-rindex 8 , -.Xr xbps-rkeys 8 +.Xr xbps-rindex 8 .Sh AUTHORS .An Juan Romero Pardines .Sh BUGS diff --git a/bin/xbps-reconfigure/xbps-reconfigure.8 b/bin/xbps-reconfigure/xbps-reconfigure.8 index b2344d73..c998ba31 100644 --- a/bin/xbps-reconfigure/xbps-reconfigure.8 +++ b/bin/xbps-reconfigure/xbps-reconfigure.8 @@ -65,8 +65,7 @@ Default cache directory to store downloaded binary packages. .Xr xbps-pkgdb 8 , .Xr xbps-query 8 , .Xr xbps-remove 8 , -.Xr xbps-rindex 8 , -.Xr xbps-rkeys 8 +.Xr xbps-rindex 8 .Sh AUTHORS .An Juan Romero Pardines .Sh BUGS diff --git a/bin/xbps-remove/xbps-remove.8 b/bin/xbps-remove/xbps-remove.8 index ab8de2f1..beafcb14 100644 --- a/bin/xbps-remove/xbps-remove.8 +++ b/bin/xbps-remove/xbps-remove.8 @@ -101,8 +101,7 @@ Default cache directory to store downloaded binary packages. .Xr xbps-pkgdb 8 , .Xr xbps-query 8 , .Xr xbps-reconfigure 8 , -.Xr xbps-rindex 8 , -.Xr xbps-rkeys 8 +.Xr xbps-rindex 8 .Sh AUTHORS .An Juan Romero Pardines .Sh BUGS diff --git a/bin/xbps-rindex/xbps-rindex.8 b/bin/xbps-rindex/xbps-rindex.8 index 74da83cf..9baa4ce8 100644 --- a/bin/xbps-rindex/xbps-rindex.8 +++ b/bin/xbps-rindex/xbps-rindex.8 @@ -66,8 +66,7 @@ architecture. .Xr xbps-pkgdb 8 , .Xr xbps-query 8 , .Xr xbps-reconfigure 8 , -.Xr xbps-remove 8 , -.Xr xbps-rkeys 8 +.Xr xbps-remove 8 .Sh AUTHORS .An Juan Romero Pardines .Sh BUGS diff --git a/bin/xbps-rkeys/Makefile b/bin/xbps-rkeys/Makefile deleted file mode 100644 index 967549b2..00000000 --- a/bin/xbps-rkeys/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -TOPDIR = ../.. --include $(TOPDIR)/config.mk - -BIN = xbps-rkeys -OBJS = main.o ../xbps-install/question.o ../xbps-install/fetch_cb.o - -include $(TOPDIR)/mk/prog.mk diff --git a/bin/xbps-rkeys/defs.h b/bin/xbps-rkeys/defs.h deleted file mode 100644 index 95bcf8bd..00000000 --- a/bin/xbps-rkeys/defs.h +++ /dev/null @@ -1,44 +0,0 @@ -/*- - * Copyright (c) 2013 Juan Romero Pardines. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _XBPS_RKEYS_DEFS_H_ -#define _XBPS_RKEYS_DEFS_H_ - -#include -#include - -struct xferstat { - struct timeval start; - struct timeval last; -}; - -/* from xbps-install/fetch_cb.c */ -void fetch_file_progress_cb(struct xbps_fetch_cb_data *, void *); - -/* from xbps-install/question.c */ -bool yesno(const char *, ...); -bool noyes(const char *, ...); - -#endif /* !_XBPS_RKEYS_DEFS_H_ */ diff --git a/bin/xbps-rkeys/main.c b/bin/xbps-rkeys/main.c deleted file mode 100644 index a39f960b..00000000 --- a/bin/xbps-rkeys/main.c +++ /dev/null @@ -1,259 +0,0 @@ -/*- - * Copyright (c) 2013 Juan Romero Pardines. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include "defs.h" - -static void __attribute__((noreturn)) -usage(bool fail) -{ - fprintf(stdout, - "Usage: xbps-rkeys [OPTIONS] [REPOURL...]\n\n" - "OPTIONS\n" - " -a --all Process all repositories in configuration file\n" - " -C --config Full path to configuration file\n" - " -d --debug Debug mode shown to stderr\n" - " -h --help Print usage help\n" - " -r --rootdir Full path to rootdir\n" - " -V --version Show XBPS version\n\n" - "MODE\n" - " -i --import Import public RSA key(s)\n" - " -R --remove Remove public RSA key(s)\n" - " -s --show Show repository info\n"); - exit(fail ? EXIT_FAILURE : EXIT_SUCCESS); -} - -static void -print_hexfp(unsigned const char *fp) -{ - unsigned int i, c, len; - - len = strlen((const char *)fp); - for (i = 0; i < len; i++) { - fprintf(stdout, "%02x", fp[i]); - c = i + 1; - if (c < len) - fprintf(stdout, ":"); - } -} - -static int -state_cb(struct xbps_state_cb_data *xscd, void *cbd _unused) -{ - int rv = 0; - - switch (xscd->state) { - /* notifications */ - case XBPS_STATE_REPO_KEY_IMPORT: - printf("%s\n", xscd->desc); - printf("Fingerprint: "); - print_hexfp((unsigned const char *)xscd->arg); - printf("\n"); - rv = noyes("Do you want to import this public key?"); - break; - case XBPS_STATE_REPOSYNC: - printf("[*] Downloading repository index `%s'...\n", xscd->arg); - break; - default: - xbps_dbg_printf(xscd->xhp, - "%s: unknown state %d\n", xscd->arg, xscd->state); - break; - } - - return rv; -} - -static int -repo_import_key_cb(struct xbps_repo *repo, void *arg _unused, bool *done _unused) -{ - int rv; - - rv = xbps_repo_key_import(repo); - if (rv != 0) - fprintf(stderr, "Failed to import pubkey from %s: %s\n", repo->uri, strerror(rv)); - - return rv; -} - -static int -repo_info_cb(struct xbps_repo *repo, void *arg _unused, bool *done _unused) -{ - xbps_dictionary_t rkeyd = NULL; - xbps_data_t rpubkey; - unsigned char *fp; - const char *signee; - uint16_t rpubkeysiz; - - if (!repo->is_remote) - return 0; - - printf("%s (%s, %s)\n", repo->uri, - repo->is_signed ? "RSA signed" : "unsigned", - repo->is_verified ? "verified" : "unverified"); - - rkeyd = xbps_dictionary_get(repo->xhp->repokeys, repo->uri); - if (xbps_object_type(rkeyd) == XBPS_TYPE_DICTIONARY) { - rpubkey = xbps_dictionary_get(rkeyd, "public-key"); - assert(rpubkey); - xbps_dictionary_get_uint16(rkeyd, "public-key-size", &rpubkeysiz); - xbps_dictionary_get_cstring_nocopy(rkeyd, "signature-by", &signee); - printf(" Signed by: %s\n", signee); - printf(" %u ", rpubkeysiz); - fp = xbps_pubkey2fp(repo->xhp, rpubkey); - assert(fp); - print_hexfp(fp); - free(fp); - printf("\n"); - } - return 0; -} - -static int -repo_remove_key_cb(struct xbps_repo *repo, void *arg, bool *done _unused) -{ - bool *flush = arg; - - if (xbps_object_type(repo->xhp->repokeys) != XBPS_TYPE_DICTIONARY) - return 0; - - xbps_dictionary_remove(repo->xhp->repokeys, repo->uri); - printf("Removed `%s' from storage.\n", repo->uri); - *flush = true; - return 0; -} - -int -main(int argc, char **argv) -{ - const char *shortopts = "aC:dhir:Rsv"; - const struct option longopts[] = { - { "all", no_argument, NULL, 'a' }, - { "config", required_argument, NULL, 'C' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "import", no_argument, NULL, 'i' }, - { "remove", no_argument, NULL, 'R' }, - { "show", no_argument, NULL, 's' }, - { "rootdir", required_argument, NULL, 'r' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 } - }; - struct xbps_handle xh; - struct xferstat xfer; - char *rkeys; - const char *conffile = NULL, *rootdir = NULL; - int c, rv, flags = 0; - bool all, flush, import, remove, show; - - all = import = remove = show = flush = false; - - while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - switch (c) { - case 'a': - all = true; - break; - case 'C': - conffile = optarg; - break; - case 'd': - flags |= XBPS_FLAG_DEBUG; - break; - case 'h': - usage(false); - /* NOTREACHED */ - case 'i': - import = true; - break; - case 'R': - remove = true; - break; - case 'r': - rootdir = optarg; - break; - case 's': - show = true; - break; - case 'V': - printf("%s\n", XBPS_RELVER); - exit(EXIT_SUCCESS); - case '?': - default: - usage(true); - /* NOTREACHED */ - } - } - if (!all && (argc == optind)) - usage(true); - - memset(&xh, 0, sizeof(xh)); - xh.fetch_cb = fetch_file_progress_cb; - xh.fetch_cb_data = &xfer; - xh.state_cb = state_cb; - xh.rootdir = rootdir; - xh.conffile = conffile; - xh.flags = flags; - - /* register specified repos */ - if (!all) { - for (int i = optind; i < argc; i++) { - if (xh.repositories == NULL) - xh.repositories = xbps_array_create(); - - xbps_array_add_cstring_nocopy(xh.repositories, argv[i]); - } - } - /* initialize libxbps */ - if ((rv = xbps_init(&xh)) != 0) { - xbps_error_printf("Failed to initialize libxbps: %s\n", - strerror(rv)); - exit(EXIT_FAILURE); - } - - if (import) { - /* Sync remote repodata first */ - xbps_rpool_sync(&xh, NULL); - rv = xbps_rpool_foreach(&xh, repo_import_key_cb, NULL); - } else if (remove) { - rv = xbps_rpool_foreach(&xh, repo_remove_key_cb, &flush); - if (flush) { - rkeys = xbps_xasprintf("%s/%s", xh.metadir, XBPS_REPOKEYS); - xbps_dictionary_externalize_to_file(xh.repokeys, rkeys); - free(rkeys); - } - } else if (show) { - rv = xbps_rpool_foreach(&xh, repo_info_cb, NULL); - } - xbps_end(&xh); - - exit(rv ? EXIT_FAILURE : EXIT_SUCCESS); -} diff --git a/bin/xbps-rkeys/xbps-rkeys.8 b/bin/xbps-rkeys/xbps-rkeys.8 deleted file mode 100644 index 8d68fd83..00000000 --- a/bin/xbps-rkeys/xbps-rkeys.8 +++ /dev/null @@ -1,61 +0,0 @@ -.Dd October 9, 2013 -.Os Void Linux -.Dt xbps-rkeys 8 -.Sh NAME -.Nm xbps-rkeys -.Nd XBPS utility to manage RSA public keys in remote repositories -.Sh SYNOPSYS -.Nm xbps-rkeys -.Op OPTIONS -.Op MODE -.Op REPOURL... -.Sh DESCRIPTION -The -.Nm -utility manages RSA public keys from remote repositories. A public key from a remote -repository can be imported and removed, last but not least there is an option to -show the repository information with details. -.Sh OPTIONS -.Bl -tag -width -x -.It Fl a, Fl -all -Processes all repositories specified in a configuration file. -.It Fl C, Fl -config Ar file -Specifies a full path to the XBPS configuration file. -.It Fl d, Fl -debug -Enables extra debugging shown to stderr. -.It Fl h, Fl -help -Show the help usage. -.It Fl r, Fl -rootdir Ar dir -Specifies a full path for the target root directory. -.It Fl V, Fl -version -Shows the XBPS version. -.Sh MODE -.Bl -tag -width -x -.It Fl i, Fl -import -Imports the RSA public key of target repository into the database. -Please double-check the fingerprint is the real one. -.It Fl R, Fl -remove -Removes the RSA public key (and its properties) of target repository from -the database. -.It Fl s, Fl -show -Shows information of the target signed repositories. -.Sh FILES -.Bl -tag -width /var/db/xbps/repokeys.plist -.It Ar /var/db/xbps/repokeys.plist -Default plist file to store repository public keys and its properties. -.Sh SEE ALSO -.Xr xbps-create 8 , -.Xr xbps-dgraph 8 , -.Xr xbps-install 8 , -.Xr xbps-pkgdb 8 , -.Xr xbps-query 8 , -.Xr xbps-reconfigure 8 , -.Xr xbps-remove 8 , -.Xr xbps-rindex 8 -.Sh AUTHORS -.An Juan Romero Pardines -.Sh BUGS -Probably, but I try to make this not happen. Use it under your own -responsability and enjoy your life. -.Pp -Report bugs in https://github.com/xtraeme/xbps/issues diff --git a/include/xbps.h.in b/include/xbps.h.in index a1306165..fb8cfb16 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -46,7 +46,7 @@ * * This header documents the full API for the XBPS Library. */ -#define XBPS_API_VERSION "20131108" +#define XBPS_API_VERSION "20131118" #ifndef XBPS_VERSION #define XBPS_VERSION "UNSET" @@ -470,7 +470,6 @@ struct xbps_handle { * @private */ cfg_t *cfg; - xbps_dictionary_t repokeys; xbps_dictionary_t pkg_metad; xbps_dictionary_t pkgdb_revdeps; /** @@ -1131,11 +1130,35 @@ struct xbps_repo { */ xbps_dictionary_t idxfiles; /** - * @var meta + * @var signature * - * Proplib dictionary associated with the repository metadata. + * RSA signature associated with this repository in a prop_data object. */ - xbps_dictionary_t meta; + xbps_data_t signature; + /** + * @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 * @@ -1152,7 +1175,6 @@ struct xbps_repo { * var is_signed * * True if this repository has been signed, false otherwise. - * (read-only). */ bool is_signed; /** @@ -1670,10 +1692,10 @@ int xbps_cmpver(const char *pkg1, const char *pkg2); * @param[in] xhp The pointer to an xbps_handle struct. * @param[in] pubkey The public-key in PEM format as xbps_data_t. * - * @return The hex fingerprint. The returned buffer must be free(3)d - * when necessary. + * @return The OpenSSH fingerprint in hexadecimal. + * The returned buffer must be free(3)d when necessary. */ -unsigned char *xbps_pubkey2fp(struct xbps_handle *xhp, xbps_data_t pubkey); +char *xbps_pubkey2fp(struct xbps_handle *xhp, xbps_data_t pubkey); /*@}*/ diff --git a/lib/initend.c b/lib/initend.c index f291bd13..704204cc 100644 --- a/lib/initend.c +++ b/lib/initend.c @@ -256,8 +256,6 @@ xbps_end(struct xbps_handle *xhp) if (xbps_object_type(xhp->pkgdb_revdeps) != XBPS_TYPE_UNKNOWN) xbps_object_release(xhp->pkgdb_revdeps); - if (xbps_object_type(xhp->repokeys) != XBPS_TYPE_UNKNOWN) - xbps_object_release(xhp->repokeys); xbps_fetch_unset_cache_connection(); cfg_free(xhp->cfg); diff --git a/lib/pubkey2fp.c b/lib/pubkey2fp.c index c674d7aa..89af9cc1 100644 --- a/lib/pubkey2fp.c +++ b/lib/pubkey2fp.c @@ -43,7 +43,26 @@ SshEncodeBuffer(unsigned char *pEncoding, int bufferLen, unsigned char *pBuffer) return index + bufferLen; } -unsigned char * +static char * +fp2str(unsigned const char *fp, unsigned int len) +{ + unsigned int i, c = 0; + char res[48], cur[4]; + + for (i = 0; i < len; i++) { + if (i > 0) + c = i*3; + sprintf(cur, "%02x", fp[i]); + res[c] = cur[0]; + res[c+1] = cur[1]; + res[c+2] = ':'; + } + res[c+2] = '\0'; + + return strdup(res); +} + +char * xbps_pubkey2fp(struct xbps_handle *xhp, xbps_data_t pubkey) { EVP_MD_CTX mdctx; @@ -51,9 +70,10 @@ xbps_pubkey2fp(struct xbps_handle *xhp, xbps_data_t pubkey) RSA *pRsa = NULL; BIO *bio = NULL; const void *pubkeydata; - unsigned char *md_value = NULL; + unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned char *nBytes = NULL, *eBytes = NULL, *pEncoding = NULL; unsigned int md_len = 0; + char *hexfpstr = NULL; int index = 0, nLen = 0, eLen = 0, encodingLength = 0; ERR_load_crypto_strings(); @@ -112,14 +132,13 @@ xbps_pubkey2fp(struct xbps_handle *xhp, xbps_data_t pubkey) EVP_MD_CTX_init(&mdctx); EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL); EVP_DigestUpdate(&mdctx, pEncoding, encodingLength); - md_value = malloc(EVP_MAX_MD_SIZE); - if (EVP_DigestFinal_ex(&mdctx, md_value, &md_len) == 0) { - free(md_value); - md_value = NULL; - } else { - md_value[md_len] = '\0'; - } + if (EVP_DigestFinal_ex(&mdctx, md_value, &md_len) == 0) + goto error; EVP_MD_CTX_cleanup(&mdctx); + /* + * Convert result to a compatible OpenSSH hex fingerprint. + */ + hexfpstr = fp2str(md_value, md_len); error: if (bio) @@ -138,5 +157,5 @@ error: EVP_cleanup(); ERR_free_strings(); - return md_value; + return hexfpstr; } diff --git a/lib/repo.c b/lib/repo.c index e3c29792..6e9f237b 100644 --- a/lib/repo.c +++ b/lib/repo.c @@ -91,6 +91,7 @@ repo_get_dict(struct xbps_repo *repo, const char *fname) 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; @@ -119,14 +120,12 @@ xbps_repo_open(struct xbps_handle *xhp, const char *url) repofile = xbps_repo_path(xhp, url); } - repo = malloc(sizeof(struct xbps_repo)); + repo = calloc(1, sizeof(struct xbps_repo)); assert(repo); repo->xhp = xhp; repo->uri = url; repo->ar = archive_read_new(); - repo->is_verified = false; - repo->is_signed = false; repo->is_remote = is_remote; archive_read_support_compression_gzip(repo->ar); archive_read_support_format_tar(repo->ar); @@ -157,10 +156,18 @@ xbps_repo_open(struct xbps_handle *xhp, const char *url) repo = NULL; goto out; } - if ((repo->meta = repo_get_dict(repo, XBPS_REPOIDX_META))) - repo->is_signed = true; + if (!is_remote) + goto out; + + if ((meta = repo_get_dict(repo, XBPS_REPOIDX_META))) { + repo->is_signed = true; + repo->signature = xbps_dictionary_get(meta, "signature"); + xbps_dictionary_get_cstring_nocopy(meta, "signature-by", &repo->signedby); + repo->pubkey = xbps_dictionary_get(meta, "public-key"); + xbps_dictionary_get_uint16(meta, "public-key-size", &repo->pubkey_size); + repo->hexfp = xbps_pubkey2fp(repo->xhp, repo->pubkey); + } - repo->idxfiles = NULL; out: free(repofile); return repo; @@ -198,10 +205,6 @@ xbps_repo_close(struct xbps_repo *repo) if (repo->ar != NULL) archive_read_finish(repo->ar); - if (repo->meta != NULL) { - xbps_object_release(repo->meta); - repo->meta = NULL; - } if (repo->idx != NULL) { xbps_object_release(repo->idx); repo->idx = NULL; @@ -210,6 +213,8 @@ xbps_repo_close(struct xbps_repo *repo) xbps_object_release(repo->idxfiles); repo->idxfiles = NULL; } + if (repo->hexfp != NULL) + free(repo->hexfp); } xbps_dictionary_t diff --git a/lib/repo_keys.c b/lib/repo_keys.c index b5db3d96..f2166615 100644 --- a/lib/repo_keys.c +++ b/lib/repo_keys.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -39,11 +40,8 @@ int xbps_repo_key_import(struct xbps_repo *repo) { - xbps_dictionary_t repokeyd, newmetad = NULL; - xbps_data_t rpubkey; - const char *signedby; - unsigned char *fp = NULL; - char *rkeypath = NULL; + xbps_dictionary_t repokeyd = NULL; + char *p, *dbkeyd, *rkeyfile = NULL; int import, rv = 0; assert(repo); @@ -55,93 +53,80 @@ xbps_repo_key_import(struct xbps_repo *repo) /* * If repository does not have required metadata plist, ignore it. */ - if (xbps_dictionary_count(repo->meta) == 0) { + if (repo->signature == NULL && repo->pubkey == NULL) { xbps_dbg_printf(repo->xhp, "[repo] `%s' unsigned repository!\n", repo->uri); return 0; } - /* - * Check if the public key has been stored for this repository. - */ - rkeypath = xbps_xasprintf("%s/%s", repo->xhp->metadir, XBPS_REPOKEYS); - if (repo->xhp->repokeys == NULL) { - repo->xhp->repokeys = xbps_dictionary_internalize_from_file(rkeypath); - if (xbps_object_type(repo->xhp->repokeys) != XBPS_TYPE_DICTIONARY) - repo->xhp->repokeys = xbps_dictionary_create(); - } - repokeyd = xbps_dictionary_get(repo->xhp->repokeys, repo->uri); - if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) { - if (xbps_dictionary_get(repokeyd, "public-key")) { - xbps_dbg_printf(repo->xhp, - "[repo] `%s' public key already stored.\n", - repo->uri); - goto out; - } - } /* * Check the repository provides a working public-key data object. */ - rpubkey = xbps_dictionary_get(repo->meta, "public-key"); - if (xbps_object_type(rpubkey) != XBPS_TYPE_DATA) { - rv = EINVAL; + repo->is_signed = true; + if (repo->hexfp == NULL) { xbps_dbg_printf(repo->xhp, - "[repo] `%s' invalid public-key object!\n", repo->uri); + "[repo] `%s': invalid hex fingerprint: %s\n", + repo->uri, strerror(errno)); + rv = EINVAL; + goto out; + } + /* + * Check if the public key is alredy stored. + */ + rkeyfile = xbps_xasprintf("%s/keys/%s.plist", + repo->xhp->metadir, repo->hexfp); + repokeyd = xbps_dictionary_internalize_from_zfile(rkeyfile); + if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) { + xbps_dbg_printf(repo->xhp, + "[repo] `%s' public key already stored.\n", repo->uri); goto out; } - repo->is_signed = true; /* * Notify the client and take appropiate action to import * the repository public key. Pass back the public key openssh fingerprint * to the client. */ - fp = xbps_pubkey2fp(repo->xhp, rpubkey); - if (fp == NULL) { - xbps_dbg_printf(repo->xhp, - "[repo] `%s': failed to compute hex fingerprint: %s\n", - repo->uri, strerror(errno)); - rv = EINVAL; - goto out; - } - xbps_dictionary_get_cstring_nocopy(repo->meta, "signature-by", &signedby); - import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, - 0, (const char *)fp, - "`%s' repository is RSA signed by \"%s\"", - repo->uri, signedby); - free(fp); + 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); if (import <= 0) { rv = EAGAIN; goto out; } - /* - * Add the meta dictionary into XBPS_REPOKEYS and externalize it. - */ - newmetad = xbps_dictionary_copy_mutable(repo->meta); - xbps_dictionary_remove(newmetad, "signature"); - xbps_dictionary_set(repo->xhp->repokeys, repo->uri, newmetad); - if (access(repo->xhp->metadir, R_OK|W_OK) == -1) { + p = strdup(rkeyfile); + dbkeyd = dirname(p); + assert(dbkeyd); + if (access(dbkeyd, R_OK|W_OK) == -1) { if (errno == ENOENT) { - xbps_mkpath(repo->xhp->metadir, 0755); + xbps_mkpath(dbkeyd, 0755); } else { rv = errno; xbps_dbg_printf(repo->xhp, - "[repo] `%s' cannot create metadir: %s\n", - repo->uri, strerror(errno)); + "[repo] `%s' cannot create %s: %s\n", + repo->uri, dbkeyd, strerror(errno)); + free(p); goto out; } } - if (!xbps_dictionary_externalize_to_file(repo->xhp->repokeys, rkeypath)) { + 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); + + if (!xbps_dictionary_externalize_to_zfile(repokeyd, rkeyfile)) { rv = errno; xbps_dbg_printf(repo->xhp, "[repo] `%s' failed to externalize %s: %s\n", - repo->uri, XBPS_REPOKEYS, strerror(rv)); + repo->uri, rkeyfile, strerror(rv)); } out: - if (newmetad) - xbps_object_release(newmetad); - if (rkeypath) - free(rkeypath); + if (repokeyd) + xbps_object_release(repokeyd); + if (rkeyfile) + free(rkeyfile); return rv; } @@ -195,32 +180,36 @@ int HIDDEN xbps_repo_key_verify(struct xbps_repo *repo) { xbps_dictionary_t repokeyd; - xbps_data_t sigdata, pubkey; - char *idx_xml; + xbps_data_t xbps_pubkey; + char *idx_xml, *rkeyfile; - if (repo->xhp->repokeys == NULL) - return ENOENT; + if (!repo->signature || !repo->hexfp) + return EINVAL; - repokeyd = xbps_dictionary_get(repo->xhp->repokeys, repo->uri); - if (xbps_dictionary_count(repokeyd) == 0) { - xbps_dbg_printf(repo->xhp, - "[repo] `%s': empty %s dictionary\n", - repo->uri, XBPS_REPOKEYS); - return ENOENT; + rkeyfile = xbps_xasprintf("%s/keys/%s.plist", + repo->xhp->metadir, repo->hexfp); + repokeyd = xbps_dictionary_internalize_from_zfile(rkeyfile); + free(rkeyfile); + if (xbps_object_type(repokeyd) != XBPS_TYPE_DICTIONARY) + return EINVAL; + + xbps_pubkey = xbps_dictionary_get(repokeyd, "public-key"); + if (xbps_object_type(xbps_pubkey) != XBPS_TYPE_DATA) { + xbps_object_release(repokeyd); + return EINVAL; } idx_xml = xbps_dictionary_externalize(repo->idx); - assert(idx_xml); + if (idx_xml == NULL) { + xbps_object_release(repokeyd); + return EINVAL; + } - sigdata = xbps_dictionary_get(repo->meta, "signature"); - assert(xbps_object_type(sigdata) == XBPS_TYPE_DATA); - pubkey = xbps_dictionary_get(repokeyd, "public-key"); - assert(xbps_object_type(pubkey) == XBPS_TYPE_DATA); - /* XXX ignore 'signature-type' for now */ - if (rsa_verify_buf(repo, sigdata, pubkey, idx_xml) == 0) + if (rsa_verify_buf(repo, repo->signature, xbps_pubkey, idx_xml) == 0) repo->is_verified = true; free(idx_xml); + xbps_object_release(repokeyd); return repo->is_verified ? 0 : EPERM; } diff --git a/lib/rpool.c b/lib/rpool.c index 85fa5ec3..a6e052b4 100644 --- a/lib/rpool.c +++ b/lib/rpool.c @@ -52,7 +52,6 @@ xbps_rpool_init(struct xbps_handle *xhp) { struct rpool *rp; const char *repouri; - char *p; bool foundrepo = false; int retval, rv = 0; @@ -61,10 +60,6 @@ xbps_rpool_init(struct xbps_handle *xhp) if (xhp->rpool_initialized) return 0; - p = xbps_xasprintf("%s/%s", xhp->metadir, XBPS_REPOKEYS); - xhp->repokeys = xbps_dictionary_internalize_from_file(p); - free(p); - for (unsigned int i = 0; i < xbps_array_count(xhp->repositories); i++) { rp = malloc(sizeof(struct rpool)); assert(rp); @@ -89,10 +84,12 @@ xbps_rpool_init(struct xbps_handle *xhp) retval = xbps_repo_key_verify(rp->repo); if (retval == 0) { /* signed, verified */ - xbps_set_cb_state(xhp, XBPS_STATE_REPO_SIGVERIFIED, 0, NULL, NULL); + xbps_set_cb_state(xhp, XBPS_STATE_REPO_SIGVERIFIED, + 0, repouri, NULL); } else if (retval == EPERM) { /* signed, unverified */ - xbps_set_cb_state(xhp, XBPS_STATE_REPO_SIGUNVERIFIED, 0, NULL, NULL); + xbps_set_cb_state(xhp, XBPS_STATE_REPO_SIGUNVERIFIED, + 0, repouri, NULL); xbps_repo_invalidate(rp->repo); } else { /* any error */