Redo how the repository keys are stored.

- Repository keys are now stored in a new directory on metadir (/var/db/xbps):

	<metadir>/key>

- Repository keys are stored with the hex fingerprint of its RSA
  public key in a plist dictionary:

	<metadir>/keys/xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx.plist

- Drop xbps-rkeys(8) and merge its functionality into xbps-install(8) and
  xbps-query(8).

- xbps-query(8) -vL now shows some more details of remote repositories:

 3134 http://localhost:8000 (RSA signed, verified)
      Signed-by: Void Linux
      4096 60:ae:0c:d6:f0:95:17:80:bc:93:46:7a:89:af:a3:2d
   16 http://localhost:8000/nonfree (RSA signed, verified)
      Signed-by: Void Linux
      4096 60:ae:0c:d6:f0:95:17:80:bc:93:46:7a:89:af:a3:2d

Bump XBPS_API_VERSION.
This commit is contained in:
Juan RP 2013-11-18 16:05:46 +01:00
parent c9825feb29
commit 8882b0215f
22 changed files with 183 additions and 509 deletions

6
NEWS
View File

@ -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 <foo@bar>" --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 <repourl>
$ 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.

View File

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

View File

@ -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 <xtraeme@gmail.com>
.Sh BUGS

View File

@ -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))

View File

@ -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:

View File

@ -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 <xtraeme@gmail.com>
.Sh BUGS

View File

@ -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 <xtraeme@gmail.com>
.Sh BUGS

View File

@ -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;
}

View File

@ -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 <xtraeme@gmail.com>
.Sh BUGS

View File

@ -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 <xtraeme@gmail.com>
.Sh BUGS

View File

@ -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 <xtraeme@gmail.com>
.Sh BUGS

View File

@ -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 <xtraeme@gmail.com>
.Sh BUGS

View File

@ -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

View File

@ -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 <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_ */

View File

@ -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 <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 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);
}

View File

@ -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 <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 "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);
/*@}*/

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -27,6 +27,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libgen.h>
#include <openssl/err.h>
#include <openssl/sha.h>
@ -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;
}

View File

@ -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 */