New utility: xbps-rkeys(8) to manage RSA public keys.

This commit is contained in:
Juan RP 2013-10-09 10:13:07 +02:00
parent 250916fa6a
commit a5ecaa493f
14 changed files with 406 additions and 37 deletions

1
.gitignore vendored
View File

@ -13,6 +13,7 @@ bin/xbps-reconfigure/xbps-reconfigure
bin/xbps-remove/xbps-remove
bin/xbps-rindex/xbps-rindex
bin/xbps-uhelper/xbps-uhelper
bin/xbps-rkeys/xbps-rkeys
*.static
*.so*
*.o

9
NEWS
View File

@ -3,14 +3,17 @@ xbps-0.27 (???):
* xbps-rindex(8): -c --clean mode has been removed. Generating a local repository
is almost as fast as cleaning up the repository data.
* 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 -s --signedby "foobar <foo@bar>" --privkey /priv/key /path/to/repo
The first time xbps-install(8) access to a signed repository it will ask you
to import its public key to verify the signature. Please double-check the
hex fingerprint of the public key is the real one!
Public keys must be imported before using a remote signed repository thru
the xbps-rkeys(8) utility:
$ xbps-rkeys -i <repourl>
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.

View File

@ -9,5 +9,6 @@ SUBDIRS += xbps-reconfigure
SUBDIRS += xbps-remove
SUBDIRS += xbps-rindex
SUBDIRS += xbps-uhelper
SUBDIRS += xbps-rkeys
include ../mk/subdir.mk

View File

@ -47,13 +47,6 @@ state_cb(struct xbps_state_cb_data *xscd, void *cbdata _unused)
switch (xscd->state) {
/* notifications */
case XBPS_STATE_REPO_KEY_IMPORT:
printf("%s\n", xscd->desc);
printf("Fingerprint: ");
xbps_print_hexfp(xscd->arg);
printf("\n");
rv = noyes("Do you want to import this public key?");
break;
case XBPS_STATE_REPO_SIGVERIFIED:
printf("[*] RSA signature verified correctly\n");
break;

7
bin/xbps-rkeys/Makefile Normal file
View File

@ -0,0 +1,7 @@
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

44
bin/xbps-rkeys/defs.h Normal file
View File

@ -0,0 +1,44 @@
/*-
* 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 <sys/time.h>
#include <xbps.h>
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_ */

239
bin/xbps-rkeys/main.c Normal file
View File

@ -0,0 +1,239 @@
/*-
* 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 <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <assert.h>
#include <xbps.h>
#include "defs.h"
static void __attribute__((noreturn))
usage(bool fail)
{
fprintf(stdout,
"Usage: xbps-rkeys [OPTIONS] <MODE> [REPOURL...]\n\n"
"OPTIONS\n"
" -a --all Process all repositories in configuration file\n"
" -C --config <file> Full path to configuration file\n"
" -d --debug Debug mode shown to stderr\n"
" -h --help Print usage help\n"
" -r --rootdir <dir> 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 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: ");
xbps_print_hexfp(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)
{
return xbps_repo_key_import(repo);
}
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);
xbps_print_hexfp((const char *)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);
}

View File

@ -0,0 +1,61 @@
.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 <xtraeme@gmail.com>
.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

View File

@ -46,7 +46,7 @@
*
* This header documents the full API for the XBPS Library.
*/
#define XBPS_API_VERSION "20131007"
#define XBPS_API_VERSION "20131009"
#ifndef XBPS_VERSION
#define XBPS_VERSION "UNSET"
@ -1281,6 +1281,7 @@ struct xbps_repo *xbps_repo_open(struct xbps_handle *xhp, const char *url);
*/
void xbps_repo_close(struct xbps_repo *repo);
/**
* Prepares the repository index-files.plist to have access to it.
* The repository must be opened previously with \a xbps_repo_open().
@ -1350,6 +1351,16 @@ xbps_dictionary_t xbps_repo_get_pkg_plist(struct xbps_handle *xhp,
*/
xbps_array_t xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg);
/**
* Imports the RSA public key of target repository. The repository must be
* signed properly for this to work.
*
* @param[in] repo Pointer to the target xbps_repo structure.
*
* @return 0 on success, an errno value otherwise.
*/
int xbps_repo_key_import(struct xbps_repo *repo);
/*@}*/
/** @addtogroup archive_util */

View File

@ -156,11 +156,16 @@ int HIDDEN xbps_entry_install_conf_file(struct xbps_handle *,
const char *,
const char *);
/**
* @private
* From lib/repo.c
*/
void HIDDEN xbps_repo_invalidate(struct xbps_repo *);
/**
* @private
* From lib/repo_keys.c
*/
int HIDDEN xbps_repo_key_import(struct xbps_repo *);
int HIDDEN xbps_repo_key_verify(struct xbps_repo *);
/**

View File

@ -253,10 +253,13 @@ xbps_end(struct xbps_handle *xhp)
xbps_pkgdb_release(xhp);
xbps_rpool_release(xhp);
xbps_fetch_unset_cache_connection();
if (xhp->pkgdb_revdeps != NULL)
xbps_object_release(xhp->pkgdb_revdeps);
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);
free(xhp->cachedir_priv);
free(xhp->metadir_priv);

View File

@ -172,6 +172,24 @@ xbps_repo_open_idxfiles(struct xbps_repo *repo)
repo->idxfiles = repo_get_dict(repo, XBPS_REPOIDX_FILES);
}
void HIDDEN
xbps_repo_invalidate(struct xbps_repo *repo)
{
if (repo->ar != NULL) {
archive_read_finish(repo->ar);
repo->ar = NULL;
}
if (repo->idx != NULL) {
xbps_object_release(repo->idx);
repo->idx = NULL;
}
if (repo->idxfiles != NULL) {
xbps_object_release(repo->idxfiles);
repo->idxfiles = NULL;
}
repo->is_verified = false;
}
void
xbps_repo_close(struct xbps_repo *repo)
{

View File

@ -36,7 +36,7 @@
#include "xbps_api_impl.h"
int HIDDEN
int
xbps_repo_key_import(struct xbps_repo *repo)
{
xbps_dictionary_t repokeyd, newmetad = NULL;
@ -58,8 +58,8 @@ xbps_repo_key_import(struct xbps_repo *repo)
/*
* 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) {
rkeypath = xbps_xasprintf("%s/%s", repo->xhp->metadir, XBPS_REPOKEYS);
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();

View File

@ -78,23 +78,9 @@ xbps_rpool_init(struct xbps_handle *xhp)
rp->repo->is_remote = true;
}
if (rp->repo->is_remote) {
/*
* Import the RSA public key (if it's signed).
*/
retval = xbps_repo_key_import(rp->repo);
if (retval == EAGAIN) {
/* signed but public key was not imported */
xbps_dbg_printf(xhp, "[rpool] `%s': public-key not yet imported.\n", repouri);
rp->repo->is_signed = true;
rp->repo->is_verified = false;
} else if (retval != 0 && retval != EAGAIN) {
/* any error */
xbps_dbg_printf(xhp, "[rpool] %s: key_import %s\n",
repouri, strerror(retval));
}
if (!rp->repo->is_signed) {
/* ignore unsigned repositories */
xbps_repo_close(rp->repo);
xbps_repo_invalidate(rp->repo);
} else {
/*
* Check the repository index signature against
@ -107,13 +93,12 @@ xbps_rpool_init(struct xbps_handle *xhp)
} else if (retval == EPERM) {
/* signed, unverified */
xbps_set_cb_state(xhp, XBPS_STATE_REPO_SIGUNVERIFIED, 0, NULL, NULL);
xbps_repo_close(rp->repo);
rp->repo->is_verified = false;
xbps_repo_invalidate(rp->repo);
} else {
/* any error */
xbps_dbg_printf(xhp, "[rpool] %s: key_verify %s\n",
repouri, strerror(retval));
xbps_repo_close(rp->repo);
xbps_repo_invalidate(rp->repo);
}
}
}
@ -155,8 +140,6 @@ xbps_rpool_release(struct xbps_handle *xhp)
free(rp->repo);
free(rp);
}
xbps_object_release(xhp->repokeys);
xhp->repokeys = NULL;
xhp->rpool_initialized = false;
xbps_dbg_printf(xhp, "[rpool] released ok.\n");
}