Added support for the long awaited feature: RSA signed repositories.
This commit is contained in:
@@ -38,11 +38,11 @@ OBJS += package_remove.o package_find_obsoletes.o package_state.o
|
||||
OBJS += package_unpack.o package_register.o package_script.o
|
||||
OBJS += transaction_commit.o transaction_package_replace.o
|
||||
OBJS += transaction_dictionary.o transaction_sortdeps.o transaction_ops.o
|
||||
OBJS += transaction_revdeps.o
|
||||
OBJS += transaction_revdeps.o pubkey2fp.o
|
||||
OBJS += download.o initend.o pkgdb.o package_conflicts.o
|
||||
OBJS += plist.o plist_find.o plist_match.o archive.o
|
||||
OBJS += plist_remove.o plist_fetch.o util.o util_hash.o
|
||||
OBJS += repo.o repo_pkgdeps.o repo_sync.o
|
||||
OBJS += repo.o repo_pkgdeps.o repo_sync.o repo_keys.o
|
||||
OBJS += rpool.o rpool_get.o cb_util.o proplib_wrapper.o
|
||||
OBJS += $(EXTOBJS) $(COMPAT_SRCS)
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ xbps_set_cb_fetch(struct xbps_handle *xhp,
|
||||
(*xhp->fetch_cb)(&xfcd, xhp->fetch_cb_data);
|
||||
}
|
||||
|
||||
void HIDDEN
|
||||
int HIDDEN
|
||||
xbps_set_cb_state(struct xbps_handle *xhp,
|
||||
xbps_state_t state,
|
||||
int err,
|
||||
@@ -84,7 +84,7 @@ xbps_set_cb_state(struct xbps_handle *xhp,
|
||||
int retval;
|
||||
|
||||
if (xhp->state_cb == NULL)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
xscd.xhp = xhp;
|
||||
xscd.state = state;
|
||||
@@ -99,7 +99,9 @@ xbps_set_cb_state(struct xbps_handle *xhp,
|
||||
else
|
||||
xscd.desc = buf;
|
||||
}
|
||||
(*xhp->state_cb)(&xscd, xhp->state_cb_data);
|
||||
retval = (*xhp->state_cb)(&xscd, xhp->state_cb_data);
|
||||
if (buf != NULL)
|
||||
free(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
143
lib/pubkey2fp.c
Normal file
143
lib/pubkey2fp.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* An implementation of convertion from OpenSSL to OpenSSH public key format
|
||||
*
|
||||
* Copyright (c) 2008 Mounir IDRASSI <mounir.idrassi@idrix.fr>. All rights reserved.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "xbps_api_impl.h"
|
||||
|
||||
static unsigned char pSshHeader[11] = {
|
||||
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61
|
||||
};
|
||||
|
||||
static
|
||||
int SshEncodeBuffer(unsigned char *pEncoding, int bufferLen,
|
||||
unsigned char *pBuffer)
|
||||
{
|
||||
int adjustedLen = bufferLen, index;
|
||||
|
||||
if (*pBuffer & 0x80) {
|
||||
adjustedLen++;
|
||||
pEncoding[4] = 0;
|
||||
index = 5;
|
||||
} else {
|
||||
index = 4;
|
||||
}
|
||||
pEncoding[0] = (unsigned char) (adjustedLen >> 24);
|
||||
pEncoding[1] = (unsigned char) (adjustedLen >> 16);
|
||||
pEncoding[2] = (unsigned char) (adjustedLen >> 8);
|
||||
pEncoding[3] = (unsigned char) (adjustedLen );
|
||||
memcpy(&pEncoding[index], pBuffer, bufferLen);
|
||||
return index + bufferLen;
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
xbps_pubkey2fp(struct xbps_handle *xhp, xbps_data_t pubkey)
|
||||
{
|
||||
EVP_MD_CTX mdctx;
|
||||
EVP_PKEY *pPubKey = NULL;
|
||||
RSA *pRsa = NULL;
|
||||
BIO *bio = NULL;
|
||||
const void *pubkeydata;
|
||||
unsigned char *fpstr = NULL, md_value[EVP_MAX_MD_SIZE];
|
||||
unsigned char *nBytes = NULL, *eBytes = NULL, *pEncoding = NULL;
|
||||
unsigned int md_len = 0;
|
||||
int index = 0, nLen = 0, eLen = 0, encodingLength = 0;
|
||||
|
||||
ERR_load_crypto_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
pubkeydata = xbps_data_data_nocopy(pubkey);
|
||||
bio = BIO_new_mem_buf(__UNCONST(pubkeydata), xbps_data_size(pubkey));
|
||||
assert(bio);
|
||||
|
||||
pPubKey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
|
||||
if (!pPubKey) {
|
||||
xbps_dbg_printf(xhp,
|
||||
"unable to decode public key from the given file: %s\n",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_type(pPubKey->type) != EVP_PKEY_RSA) {
|
||||
xbps_dbg_printf(xhp, "only RSA public keys are currently supported\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pRsa = EVP_PKEY_get1_RSA(pPubKey);
|
||||
if (!pRsa) {
|
||||
xbps_dbg_printf(xhp, "failed to get RSA public key : %s\n",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
// reading the modulus
|
||||
nLen = BN_num_bytes(pRsa->n);
|
||||
nBytes = (unsigned char*) malloc(nLen);
|
||||
BN_bn2bin(pRsa->n, nBytes);
|
||||
|
||||
// reading the public exponent
|
||||
eLen = BN_num_bytes(pRsa->e);
|
||||
eBytes = (unsigned char*) malloc(eLen);
|
||||
BN_bn2bin(pRsa->e, eBytes);
|
||||
|
||||
encodingLength = 11 + 4 + eLen + 4 + nLen;
|
||||
// correct depending on the MSB of e and N
|
||||
if (eBytes[0] & 0x80)
|
||||
encodingLength++;
|
||||
if (nBytes[0] & 0x80)
|
||||
encodingLength++;
|
||||
|
||||
pEncoding = malloc(encodingLength);
|
||||
memcpy(pEncoding, pSshHeader, 11);
|
||||
|
||||
index = SshEncodeBuffer(&pEncoding[11], eLen, eBytes);
|
||||
index = SshEncodeBuffer(&pEncoding[11 + index], nLen, nBytes);
|
||||
|
||||
/*
|
||||
* Compute the RSA fingerprint (MD5).
|
||||
*/
|
||||
EVP_MD_CTX_init(&mdctx);
|
||||
EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL);
|
||||
assert(EVP_DigestUpdate(&mdctx, pEncoding, encodingLength) != -1);
|
||||
assert(EVP_DigestFinal_ex(&mdctx, md_value, &md_len) != -1);
|
||||
EVP_MD_CTX_cleanup(&mdctx);
|
||||
|
||||
fpstr = malloc(md_len+1);
|
||||
for (unsigned int i = 0; i < md_len; i++)
|
||||
fpstr[i] = md_value[i];
|
||||
|
||||
fpstr[md_len] = '\0';
|
||||
|
||||
error:
|
||||
if (bio)
|
||||
BIO_free_all(bio);
|
||||
if (pRsa)
|
||||
RSA_free(pRsa);
|
||||
if (pPubKey)
|
||||
EVP_PKEY_free(pPubKey);
|
||||
if (nBytes)
|
||||
free(nBytes);
|
||||
if (eBytes)
|
||||
free(eBytes);
|
||||
if (pEncoding)
|
||||
free(pEncoding);
|
||||
|
||||
EVP_cleanup();
|
||||
ERR_free_strings();
|
||||
|
||||
return fpstr;
|
||||
}
|
||||
44
lib/repo.c
44
lib/repo.c
@@ -88,16 +88,17 @@ xbps_repo_open(struct xbps_handle *xhp, const char *url)
|
||||
archive_read_support_format_tar(repo->ar);
|
||||
|
||||
if (stat(repofile, &st) == -1) {
|
||||
xbps_dbg_printf(xhp, "[repo] cannot stat repository file %s: %s\n",
|
||||
repofile, strerror(errno));
|
||||
xbps_dbg_printf(xhp, "[repo] `%s' missing repodata %s: %s\n",
|
||||
url, repofile, strerror(errno));
|
||||
archive_read_finish(repo->ar);
|
||||
free(repo);
|
||||
repo = NULL;
|
||||
goto out;
|
||||
}
|
||||
if (archive_read_open_filename(repo->ar, repofile, st.st_blksize) == ARCHIVE_FATAL) {
|
||||
xbps_dbg_printf(xhp, "[repo] cannot open repository file %s: %s\n",
|
||||
repofile, strerror(archive_errno(repo->ar)));
|
||||
xbps_dbg_printf(xhp,
|
||||
"[repo] `%s' failed to open repodata archive %s: %s\n",
|
||||
url, repofile, strerror(archive_errno(repo->ar)));
|
||||
archive_read_finish(repo->ar);
|
||||
free(repo);
|
||||
repo = NULL;
|
||||
@@ -152,15 +153,21 @@ xbps_repo_close(struct xbps_repo *repo)
|
||||
{
|
||||
assert(repo);
|
||||
|
||||
if (repo->ar == NULL)
|
||||
return;
|
||||
if (repo->ar != NULL)
|
||||
archive_read_finish(repo->ar);
|
||||
|
||||
archive_read_finish(repo->ar);
|
||||
if (xbps_object_type(repo->idx) == XBPS_TYPE_DICTIONARY)
|
||||
if (repo->meta != NULL) {
|
||||
xbps_object_release(repo->meta);
|
||||
repo->meta = NULL;
|
||||
}
|
||||
if (repo->idx != NULL) {
|
||||
xbps_object_release(repo->idx);
|
||||
if (xbps_object_type(repo->idxfiles) == XBPS_TYPE_DICTIONARY)
|
||||
repo->idx = NULL;
|
||||
}
|
||||
if (repo->idxfiles != NULL) {
|
||||
xbps_object_release(repo->idxfiles);
|
||||
free(repo);
|
||||
repo->idxfiles = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
xbps_dictionary_t
|
||||
@@ -171,14 +178,9 @@ xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg)
|
||||
assert(repo);
|
||||
assert(pkg);
|
||||
|
||||
if (repo->ar == NULL)
|
||||
if (repo->ar == NULL || repo->idx == NULL)
|
||||
return NULL;
|
||||
|
||||
if (xbps_object_type(repo->idx) != XBPS_TYPE_DICTIONARY) {
|
||||
repo->idx = xbps_repo_get_plist(repo, XBPS_PKGINDEX);
|
||||
if (repo->idx == NULL)
|
||||
return NULL;
|
||||
}
|
||||
pkgd = xbps_find_virtualpkg_in_dict(repo->xhp, repo->idx, pkg);
|
||||
if (pkgd) {
|
||||
xbps_dictionary_set_cstring_nocopy(pkgd,
|
||||
@@ -196,14 +198,9 @@ xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg)
|
||||
assert(repo);
|
||||
assert(pkg);
|
||||
|
||||
if (repo->ar == NULL)
|
||||
if (repo->ar == NULL || repo->idx == NULL)
|
||||
return NULL;
|
||||
|
||||
if (xbps_object_type(repo->idx) != XBPS_TYPE_DICTIONARY) {
|
||||
repo->idx = xbps_repo_get_plist(repo, XBPS_PKGINDEX);
|
||||
if (repo->idx == NULL)
|
||||
return NULL;
|
||||
}
|
||||
pkgd = xbps_find_pkg_in_dict(repo->idx, pkg);
|
||||
if (pkgd) {
|
||||
xbps_dictionary_set_cstring_nocopy(pkgd,
|
||||
@@ -336,6 +333,9 @@ xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg)
|
||||
char *buf = NULL;
|
||||
bool match = false;
|
||||
|
||||
if (repo->idx == NULL)
|
||||
return NULL;
|
||||
|
||||
if (((pkgd = xbps_rpool_get_pkg(repo->xhp, pkg)) == NULL) &&
|
||||
((pkgd = xbps_rpool_get_virtualpkg(repo->xhp, pkg)) == NULL)) {
|
||||
errno = ENOENT;
|
||||
|
||||
233
lib/repo_keys.c
Normal file
233
lib/repo_keys.c
Normal file
@@ -0,0 +1,233 @@
|
||||
/*-
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include "xbps_api_impl.h"
|
||||
|
||||
int HIDDEN
|
||||
xbps_repo_key_import(struct xbps_repo *repo)
|
||||
{
|
||||
xbps_dictionary_t repokeyd, rkeysd = NULL, newmetad = NULL;
|
||||
xbps_data_t rpubkey;
|
||||
const char *signedby;
|
||||
unsigned char *fp;
|
||||
char *rkeypath = NULL;
|
||||
int import, rv = 0;
|
||||
|
||||
assert(repo);
|
||||
/*
|
||||
* If repository does not have required metadata plist, ignore it.
|
||||
*/
|
||||
if (xbps_dictionary_count(repo->meta) == 0) {
|
||||
xbps_dbg_printf(repo->xhp,
|
||||
"[repo] `%s' missing required metadata, ignoring.\n", repo->uri);
|
||||
repo->is_verified = false;
|
||||
repo->is_signed = false;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
xbps_dbg_printf(repo->xhp,
|
||||
"[repo] `%s' invalid public-key object!\n", repo->uri);
|
||||
repo->is_verified = false;
|
||||
repo->is_signed = false;
|
||||
goto out;
|
||||
}
|
||||
repo->is_signed = true;
|
||||
/*
|
||||
* Check if the public key has been stored for this repository.
|
||||
*/
|
||||
rkeypath = xbps_xasprintf("%s/%s", repo->xhp->metadir, XBPS_REPOKEYS);
|
||||
rkeysd = xbps_dictionary_internalize_from_file(rkeypath);
|
||||
if (xbps_object_type(rkeysd) != XBPS_TYPE_DICTIONARY)
|
||||
rkeysd = xbps_dictionary_create();
|
||||
|
||||
repokeyd = xbps_dictionary_get(rkeysd, 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;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
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,
|
||||
"This repository is RSA signed by \"%s\"",
|
||||
signedby);
|
||||
free(fp);
|
||||
if (import <= 0)
|
||||
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(rkeysd, repo->uri, newmetad);
|
||||
|
||||
if (access(repo->xhp->metadir, R_OK|W_OK) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
xbps_mkpath(repo->xhp->metadir, 0755);
|
||||
} else {
|
||||
rv = errno;
|
||||
xbps_dbg_printf(repo->xhp,
|
||||
"[repo] `%s' cannot create metadir: %s\n",
|
||||
repo->uri, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (!xbps_dictionary_externalize_to_file(rkeysd, rkeypath)) {
|
||||
rv = errno;
|
||||
xbps_dbg_printf(repo->xhp,
|
||||
"[repo] `%s' failed to externalize %s: %s\n",
|
||||
repo->uri, XBPS_REPOKEYS, strerror(rv));
|
||||
}
|
||||
|
||||
out:
|
||||
if (newmetad)
|
||||
xbps_object_release(newmetad);
|
||||
if (xbps_object_type(rkeysd) == XBPS_TYPE_DICTIONARY)
|
||||
xbps_object_release(rkeysd);
|
||||
free(rkeypath);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
rsa_verify_buf(struct xbps_repo *repo, xbps_data_t sigdata,
|
||||
xbps_data_t pubkey, const char *buf)
|
||||
{
|
||||
SHA256_CTX context;
|
||||
BIO *bio;
|
||||
RSA *rsa;
|
||||
unsigned char sha256[SHA256_DIGEST_LENGTH];
|
||||
int rv = 0;
|
||||
|
||||
ERR_load_crypto_strings();
|
||||
SSL_load_error_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
OpenSSL_add_all_ciphers();
|
||||
|
||||
bio = BIO_new_mem_buf(__UNCONST(xbps_data_data_nocopy(pubkey)),
|
||||
xbps_data_size(pubkey));
|
||||
assert(bio);
|
||||
|
||||
rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
|
||||
if (rsa == NULL) {
|
||||
xbps_dbg_printf(repo->xhp,
|
||||
"[repo] `%s' error reading public key: %s\n",
|
||||
repo->uri, ERR_error_string(ERR_get_error(), NULL));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
SHA256_Init(&context);
|
||||
SHA256_Update(&context, buf, strlen(buf));
|
||||
SHA256_Final(sha256, &context);
|
||||
|
||||
if (RSA_verify(NID_sha1, sha256, sizeof(sha256),
|
||||
xbps_data_data_nocopy(sigdata),
|
||||
xbps_data_size(sigdata), rsa) == 0) {
|
||||
xbps_dbg_printf(repo->xhp,
|
||||
"[repo] `%s' failed to verify signature: %s\n",
|
||||
repo->uri, ERR_error_string(ERR_get_error(), NULL));
|
||||
rv = EPERM;
|
||||
}
|
||||
RSA_free(rsa);
|
||||
BIO_free(bio);
|
||||
ERR_free_strings();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int HIDDEN
|
||||
xbps_repo_key_verify(struct xbps_repo *repo)
|
||||
{
|
||||
xbps_dictionary_t rkeysd, repokeyd;
|
||||
xbps_data_t sigdata, pubkey;
|
||||
char *rkeyspath, *idx_xml;
|
||||
bool verified = false;
|
||||
|
||||
/* unsigned repo */
|
||||
if (!repo->is_signed) {
|
||||
xbps_dbg_printf(repo->xhp,
|
||||
"[repo] `%s' ignoring unsigned repository.\n", repo->uri);
|
||||
return 0;
|
||||
}
|
||||
rkeyspath = xbps_xasprintf("%s/%s", repo->xhp->metadir, XBPS_REPOKEYS);
|
||||
rkeysd = xbps_dictionary_internalize_from_file(rkeyspath);
|
||||
if (xbps_dictionary_count(rkeysd) == 0) {
|
||||
xbps_dbg_printf(repo->xhp,
|
||||
"[repo] `%s': failed to internalize %s: %s\n",
|
||||
repo->uri, rkeyspath, strerror(errno));
|
||||
free(rkeyspath);
|
||||
return ENODEV;
|
||||
}
|
||||
free(rkeyspath);
|
||||
|
||||
repokeyd = xbps_dictionary_get(rkeysd, repo->uri);
|
||||
if (xbps_dictionary_count(repokeyd) == 0) {
|
||||
xbps_dbg_printf(repo->xhp,
|
||||
"[repo] `%s': empty %s dictionary\n",
|
||||
repo->uri, XBPS_REPOKEYS);
|
||||
xbps_object_release(rkeysd);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
idx_xml = xbps_dictionary_externalize(repo->idx);
|
||||
assert(idx_xml);
|
||||
|
||||
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) {
|
||||
repo->is_verified = true;
|
||||
verified = true;
|
||||
}
|
||||
free(idx_xml);
|
||||
|
||||
return verified ? 0 : EPERM;
|
||||
}
|
||||
68
lib/rpool.c
68
lib/rpool.c
@@ -53,7 +53,7 @@ xbps_rpool_init(struct xbps_handle *xhp)
|
||||
struct rpool *rp;
|
||||
const char *repouri;
|
||||
bool foundrepo = false;
|
||||
int rv = 0;
|
||||
int retval, rv = 0;
|
||||
|
||||
assert(xhp);
|
||||
|
||||
@@ -65,15 +65,59 @@ xbps_rpool_init(struct xbps_handle *xhp)
|
||||
assert(rp);
|
||||
xbps_array_get_cstring_nocopy(xhp->repositories, i, &repouri);
|
||||
if ((rp->repo = xbps_repo_open(xhp, repouri)) == NULL) {
|
||||
rp->repo = calloc(1, sizeof(struct xbps_repo));
|
||||
rp->repo = malloc(sizeof(struct xbps_repo));
|
||||
assert(rp->repo);
|
||||
rp->repo->ar = NULL;
|
||||
rp->repo->is_verified = false;
|
||||
rp->repo->is_signed = false;
|
||||
}
|
||||
rp->repo->idx = xbps_repo_get_plist(rp->repo, XBPS_PKGINDEX);
|
||||
rp->repo->idx = xbps_repo_get_plist(rp->repo, XBPS_REPOIDX);
|
||||
if (xbps_object_type(rp->repo->idx) == XBPS_TYPE_DICTIONARY)
|
||||
xbps_dictionary_make_immutable(rp->repo->idx);
|
||||
|
||||
rp->repo->meta = xbps_repo_get_plist(rp->repo, XBPS_REPOMETA);
|
||||
if (xbps_object_type(rp->repo->meta) == XBPS_TYPE_DICTIONARY)
|
||||
xbps_dictionary_make_immutable(rp->repo->meta);
|
||||
|
||||
rp->repo->uri = repouri;
|
||||
rp->repo->xhp = xhp;
|
||||
|
||||
if (xbps_repository_is_remote(repouri)) {
|
||||
/*
|
||||
* Import the RSA public key (if it's signed).
|
||||
*/
|
||||
retval = xbps_repo_key_import(rp->repo);
|
||||
if (retval != 0) {
|
||||
/* any error */
|
||||
xbps_dbg_printf(xhp, "[rpool] %s: key_import %s\n",
|
||||
rp->repo->uri, strerror(retval));
|
||||
}
|
||||
/*
|
||||
* Check the repository signature against stored public key.
|
||||
*/
|
||||
retval = xbps_repo_key_verify(rp->repo);
|
||||
if (retval == 0) {
|
||||
/* signed, verified */
|
||||
xbps_set_cb_state(xhp, XBPS_STATE_REPO_SIGVERIFIED, 0, NULL, NULL);
|
||||
} else if (retval == EPERM) {
|
||||
/* signed, unverified */
|
||||
xbps_set_cb_state(xhp, XBPS_STATE_REPO_SIGUNVERIFIED, 0, NULL, NULL);
|
||||
xbps_repo_close(rp->repo);
|
||||
} else {
|
||||
/* any error */
|
||||
xbps_dbg_printf(xhp, "[rpool] %s: key_verify %s\n",
|
||||
rp->repo->uri, strerror(retval));
|
||||
xbps_repo_close(rp->repo);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If repository has passed signature checks, add it to the pool.
|
||||
*/
|
||||
SIMPLEQ_INSERT_TAIL(&rpool_queue, rp, entries);
|
||||
foundrepo = true;
|
||||
xbps_dbg_printf(xhp, "[rpool] `%s' registered.\n", repouri);
|
||||
xbps_dbg_printf(xhp, "[rpool] `%s' registered (%s, %s).\n",
|
||||
repouri, rp->repo->is_signed ? "signed" : "unsigned",
|
||||
rp->repo->is_verified ? "verified" : "unverified");
|
||||
}
|
||||
if (!foundrepo) {
|
||||
/* no repositories available, error out */
|
||||
@@ -101,6 +145,7 @@ xbps_rpool_release(struct xbps_handle *xhp)
|
||||
while ((rp = SIMPLEQ_FIRST(&rpool_queue))) {
|
||||
SIMPLEQ_REMOVE(&rpool_queue, rp, rpool, entries);
|
||||
xbps_repo_close(rp->repo);
|
||||
free(rp->repo);
|
||||
free(rp);
|
||||
}
|
||||
xhp->rpool_initialized = false;
|
||||
@@ -131,8 +176,8 @@ xbps_rpool_sync(struct xbps_handle *xhp, const char *uri)
|
||||
|
||||
int
|
||||
xbps_rpool_foreach(struct xbps_handle *xhp,
|
||||
int (*fn)(struct xbps_repo *, void *, bool *),
|
||||
void *arg)
|
||||
int (*fn)(struct xbps_repo *, void *, bool *),
|
||||
void *arg)
|
||||
{
|
||||
struct rpool *rp;
|
||||
int rv = 0;
|
||||
@@ -142,21 +187,14 @@ xbps_rpool_foreach(struct xbps_handle *xhp,
|
||||
/* Initialize repository pool */
|
||||
if ((rv = xbps_rpool_init(xhp)) != 0) {
|
||||
if (rv == ENOTSUP) {
|
||||
xbps_dbg_printf(xhp,
|
||||
"[rpool] empty repository list.\n");
|
||||
xbps_dbg_printf(xhp, "[rpool] empty repository list.\n");
|
||||
} else if (rv != ENOENT && rv != ENOTSUP) {
|
||||
xbps_dbg_printf(xhp,
|
||||
"[rpool] couldn't initialize: %s\n",
|
||||
strerror(rv));
|
||||
xbps_dbg_printf(xhp, "[rpool] couldn't initialize: %s\n", strerror(rv));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
/* Iterate over repository pool */
|
||||
SIMPLEQ_FOREACH(rp, &rpool_queue, entries) {
|
||||
/* ignore invalid repos */
|
||||
if (rp->repo->idx == NULL)
|
||||
continue;
|
||||
|
||||
rv = (*fn)(rp->repo, arg, &done);
|
||||
if (rv != 0 || done)
|
||||
break;
|
||||
|
||||
17
lib/util.c
17
lib/util.c
@@ -297,3 +297,20 @@ xbps_humanize_number(char *buf, int64_t bytes)
|
||||
return humanize_number(buf, 7, bytes, "B",
|
||||
HN_AUTOSCALE, HN_DECIMAL|HN_NOSPACE);
|
||||
}
|
||||
|
||||
void
|
||||
xbps_print_hexfp(const char *fp)
|
||||
{
|
||||
unsigned char *fpstr;
|
||||
unsigned int i, c, len;
|
||||
|
||||
fpstr = (unsigned char *)(void *)(unsigned long)(const void *)fp;
|
||||
len = strlen(fp);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
printf("%02x", fpstr[i]);
|
||||
c = i + 1;
|
||||
if (c < len)
|
||||
putchar(':');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user