Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
libpkg: abstract rsa away behind a pkgsign interface
Kyle Evans committed 2 years ago
commit 6aef91683c8d27876b06445268af9c0f9da79c72
parent c12ec89
8 files changed +891 -540
modified libpkg/Makefile.autosetup
@@ -6,7 +6,8 @@ SRCS= backup_lib.c \
	pkg_deps.c \
	pkg_repo_meta.c \
	pkg.c \
-
	rsa.c \
+
	pkgsign.c \
+
	pkgsign_ossl.c \
	clean_cache.c \
	metalog.c \
	pkg_checksum.c \
modified libpkg/pkg_repo.c
@@ -56,6 +56,7 @@
#include "private/pkg.h"
#include "private/pkgdb.h"
#include "private/fetch.h"
+
#include "private/pkgsign.h"

struct sig_cert {
	char name[MAXPATHLEN];
@@ -615,6 +616,9 @@ pkg_repo_archive_extract_check_archive(int fd, const char *file,
{
	pkghash *sc = NULL;
	struct sig_cert *s;
+
	const struct pkgsign_ctx *sctx;
+
	const char *rkey;
+
	signature_t sigtype;
	pkghash_it it;
	int ret, rc;

@@ -624,8 +628,11 @@ pkg_repo_archive_extract_check_archive(int fd, const char *file,
			!= EPKG_OK)
		return (EPKG_FATAL);

-
	if (pkg_repo_signature_type(repo) == SIG_PUBKEY) {
-
		if (pkg_repo_key(repo) == NULL) {
+
	sctx = NULL;
+
	sigtype = pkg_repo_signature_type(repo);
+
	if (sigtype == SIG_PUBKEY) {
+
		rkey = pkg_repo_key(repo);
+
		if (rkey == NULL) {
			pkg_emit_error("No PUBKEY defined. Removing "
			    "repository.");
			rc = EPKG_FATAL;
@@ -633,22 +640,40 @@ pkg_repo_archive_extract_check_archive(int fd, const char *file,
		}
		if (sc == NULL) {
			pkg_emit_error("No signature found in the repository.  "
-
					"Can not validate against %s key.", pkg_repo_key(repo));
+
					"Can not validate against %s key.", rkey);
			rc = EPKG_FATAL;
			goto out;
		}
		it = pkghash_iterator(sc);
		pkghash_next(&it); /* check that there is content is already above */
		s = (struct sig_cert *)it.value;
+

+
		ret = pkgsign_new_verify("rsa", &sctx);
+
		if (ret != EPKG_OK) {
+
			pkg_emit_error("'rsa' signer not found");
+
			rc = EPKG_FATAL;
+
			goto out;
+
		}
+

		/*
-
		 * Here are dragons:
-
		 * 1) rsa_verify is NOT rsa_verify_cert
-
		 * 2) siglen must be reduced by one to match how pkg_repo_finish()
-
		 *    packs the signature in.
+
		 * Note that pkgsign_verify is not the same method or use-case
+
		 * as pkgsign_verify_cert.
+
		 *
+
		 * The primary difference is that pkgsign_verify takes a file
+
		 * to load the pubkey from, while pkgsign_verify_cert expects
+
		 * that the key will simply be passed in for it to verify
+
		 * against.
+
		 *
+
		 * Some versions of pkgsign_verify were also suboptimal, in the
+
		 * sense that they signed the hex encoding of a SHA256 checksum
+
		 * over the repo rather than raw.  This required some kludges
+
		 * to work with, but future pkgsign_verify implementations
+
		 * should not follow in its path.
		 *
-
		 * by @bdrewery
+
		 * We reduce siglen by one to chop off the NULL terminator that
+
		 * is packed in with it over in pkg_repo_finish().
		 */
-
		ret = rsa_verify(pkg_repo_key(repo), s->sig, s->siglen - 1,
+
		ret = pkgsign_verify(sctx, rkey, s->sig, s->siglen - 1,
		    dest_fd);
		if (ret != EPKG_OK) {
			pkg_emit_error("Invalid signature, "
@@ -661,8 +686,23 @@ pkg_repo_archive_extract_check_archive(int fd, const char *file,
		it = pkghash_iterator(sc);
		while (pkghash_next(&it)) {
			s = (struct sig_cert *)it.value;
-
			ret = rsa_verify_cert(s->cert, s->certlen, s->sig, s->siglen,
-
				dest_fd);
+

+
			/*
+
			 * Each signature may use a different signer, so we'll potentially
+
			 * grab a new context for each one.  This is cheaper than it sounds,
+
			 * verifying contexts are stashed in a pkghash for re-use.
+
			 */
+
			if (sctx == NULL) {
+
				ret = pkgsign_new_verify("rsa", &sctx);
+
				if (ret != EPKG_OK) {
+
					pkg_emit_error("'rsa' signer not found");
+
					rc = EPKG_FATAL;
+
					goto out;
+
				}
+
			}
+

+
			ret = pkgsign_verify_cert(sctx, s->cert, s->certlen, s->sig,
+
			     s->siglen, dest_fd);
			if (ret == EPKG_OK && s->trusted) {
				break;
			}
@@ -867,6 +907,7 @@ pkg_repo_fetch_meta(struct pkg_repo *repo, time_t *t)
{
	char filepath[MAXPATHLEN];
	struct pkg_repo_meta *nmeta;
+
	const struct pkgsign_ctx *sctx;
	struct stat st;
	unsigned char *map = NULL;
	int fd, dbdirfd, metafd;
@@ -878,6 +919,7 @@ pkg_repo_fetch_meta(struct pkg_repo *repo, time_t *t)
	pkghash_it it;

	dbdirfd = pkg_get_dbdirfd();
+
	sctx = NULL;
	if (repo->dfd == -1) {
		if (pkg_repo_open(repo) == EPKG_FATAL)
			return (EPKG_FATAL);
@@ -985,7 +1027,21 @@ pkg_repo_fetch_meta(struct pkg_repo *repo, time_t *t)
		it = pkghash_iterator(sc);
		while (pkghash_next(&it)) {
			s = (struct sig_cert *) it.value;
-
			ret = rsa_verify_cert(s->cert, s->certlen, s->sig, s->siglen,
+

+
			/*
+
			 * Just as above, each one may have a different type associated with
+
			 * it, so grab a new one each time.
+
			 */
+
			if (sctx == NULL) {
+
				ret = pkgsign_new_verify("rsa", &sctx);
+
				if (ret != EPKG_OK) {
+
					pkg_emit_error("'rsa' signer not found");
+
					rc = EPKG_FATAL;
+
					goto cleanup;
+
				}
+
			}
+

+
			ret = pkgsign_verify_cert(sctx, s->cert, s->certlen, s->sig, s->siglen,
				metafd);
			if (ret == EPKG_OK && s->trusted)
				break;
modified libpkg/pkg_repo_create.c
@@ -56,6 +56,7 @@
#include "private/utils.h"
#include "private/pkg.h"
#include "private/pkgdb.h"
+
#include "private/pkgsign.h"

enum {
	MSG_PKG_DONE=0,
@@ -63,7 +64,7 @@ enum {
};

static int pkg_repo_pack_db(const char *name, const char *archive, char *path,
-
    struct pkg_key *keyinfo, struct pkg_repo_create *prc);
+
    struct pkgsign_ctx *ctx, struct pkg_repo_create *prc);

static int
hash_file(struct pkg_repo_meta *meta, struct pkg *pkg, char *path)
@@ -603,7 +604,7 @@ pkg_repo_create_pack_and_sign(struct pkg_repo_create *prc)
	char repo_archive[MAXPATHLEN];
	char *key_file;
	const char *key_type;
-
	struct pkg_key *keyinfo = NULL;
+
	struct pkgsign_ctx *sctx = NULL;
	struct stat st;
	int ret = EPKG_OK, nfile = 0;
	const int files_to_pack = 4;
@@ -618,7 +619,14 @@ pkg_repo_create_pack_and_sign(struct pkg_repo_create *prc)
		}

		pkg_debug(1, "Loading %s key from '%s' for signing", key_type, key_file);
-
		rsa_new(&keyinfo, prc->sign.cb, key_file);
+
		ret = pkgsign_new_sign(key_type, &sctx);
+
		if (ret != 0) {
+
			pkg_emit_error("'%s' signer not found", key_type);
+
			return (EPKG_FATAL);
+
		}
+

+
		pkgsign_set(sctx, prc->sign.cb, key_file);
+
		ret = EPKG_OK;
	}

	if (prc->sign.argc > 1 && strcmp(prc->sign.argv[0], "signing_command:") != 0)
@@ -636,7 +644,7 @@ pkg_repo_create_pack_and_sign(struct pkg_repo_create *prc)
	    prc->meta->manifests);
	snprintf(repo_archive, sizeof(repo_archive), "%s/%s", prc->outdir,
		prc->meta->manifests_archive);
-
	if (pkg_repo_pack_db(prc->meta->manifests, repo_archive, repo_path, keyinfo, prc) != EPKG_OK) {
+
	if (pkg_repo_pack_db(prc->meta->manifests, repo_archive, repo_path, sctx, prc) != EPKG_OK) {
		ret = EPKG_FATAL;
		goto cleanup;
	}
@@ -648,7 +656,7 @@ pkg_repo_create_pack_and_sign(struct pkg_repo_create *prc)
		    prc->meta->filesite);
		snprintf(repo_archive, sizeof(repo_archive), "%s/%s",
		    prc->outdir, prc->meta->filesite_archive);
-
		if (pkg_repo_pack_db(prc->meta->filesite, repo_archive, repo_path, keyinfo, prc) != EPKG_OK) {
+
		if (pkg_repo_pack_db(prc->meta->filesite, repo_archive, repo_path, sctx, prc) != EPKG_OK) {
			ret = EPKG_FATAL;
			goto cleanup;
		}
@@ -658,7 +666,7 @@ pkg_repo_create_pack_and_sign(struct pkg_repo_create *prc)
	snprintf(repo_path, sizeof(repo_path), "%s/%s", prc->outdir, prc->meta->data);
	snprintf(repo_archive, sizeof(repo_archive), "%s/%s", prc->outdir,
	    prc->meta->data_archive);
-
	if (pkg_repo_pack_db(prc->meta->data, repo_archive, repo_path, keyinfo, prc) != EPKG_OK) {
+
	if (pkg_repo_pack_db(prc->meta->data, repo_archive, repo_path, sctx, prc) != EPKG_OK) {
		ret = EPKG_FATAL;
		goto cleanup;
	}
@@ -692,7 +700,7 @@ pkg_repo_create_pack_and_sign(struct pkg_repo_create *prc)
cleanup:
	pkg_emit_progress_tick(files_to_pack, files_to_pack);

-
	rsa_free(keyinfo);
+
	pkgsign_free(sctx);

	return (ret);
}
@@ -962,16 +970,16 @@ done:
}

static int
-
pack_rsa_sign(struct packing *pack, struct pkg_key *keyinfo, const char *path,
+
pack_sign(struct packing *pack, struct pkgsign_ctx *sctx, const char *path,
    const char *name)
{
	unsigned char *sigret = NULL;
-
	unsigned int siglen = 0;
+
	size_t siglen = 0;

-
	if (keyinfo == NULL)
+
	if (sctx == NULL)
		return (EPKG_FATAL);

-
	if (rsa_sign(path, keyinfo, &sigret, &siglen) != EPKG_OK) {
+
	if (pkgsign_sign(sctx, path, &sigret, &siglen) != EPKG_OK) {
		free(sigret);
		return (EPKG_FATAL);
	}
@@ -1019,7 +1027,7 @@ pack_command_sign(struct packing *pack, const char *path, char **argv, int argc,

static int
pkg_repo_pack_db(const char *name, const char *archive, char *path,
-
    struct pkg_key *keyinfo, struct pkg_repo_create *prc)
+
    struct pkgsign_ctx *sctx, struct pkg_repo_create *prc)
{
	struct packing *pack;
	int ret = EPKG_OK;
@@ -1027,8 +1035,8 @@ pkg_repo_pack_db(const char *name, const char *archive, char *path,
	if (packing_init(&pack, archive, prc->meta->packing_format, 0, (time_t)-1, true, true) != EPKG_OK)
		return (EPKG_FATAL);

-
	if (keyinfo != NULL) {
-
		ret = pack_rsa_sign(pack, keyinfo, path, "signature");
+
	if (sctx != NULL) {
+
		ret = pack_sign(pack, sctx, path, "signature");
	} else if (prc->sign.argc >= 1) {
		ret = pack_command_sign(pack, path, prc->sign.argv, prc->sign.argc, name);
	}
added libpkg/pkgsign.c
@@ -0,0 +1,189 @@
+
/*-
+
 * Copyright (c) 2021 Kyle Evans <kevans@FreeBSD.org>
+
 *
+
 * 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
+
 *    in this position and unchanged.
+
 * 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(S) ``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(S) 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 <sys/cdefs.h>
+

+
#include <assert.h>
+
#include <errno.h>
+
#include <stdlib.h>
+
#include <string.h>
+

+
#include "private/pkg.h"
+
#include "private/pkgsign.h"
+
#include "pkghash.h"
+
#include "xmalloc.h"
+

+
/* Other parts of libpkg should use pkgsign instead of rsa directly. */
+
extern const struct pkgsign_ops	pkgsign_ossl;
+

+
static pkghash *pkgsign_verifiers;
+

+
/*
+
 * The eventual goal is to allow plugins to register their own pkgsign
+
 * implementations as needed.  The initial sketch was to add a constructor
+
 * to register the builtin pkgsign implementations since there should only be
+
 * a couple of them, but this is saved for later work.
+
 */
+
static struct pkgsign_impl {
+
	const char			*pi_name;
+
	const struct pkgsign_ops	*pi_ops;
+
	int				 pi_refs; /* XXX */
+
} pkgsign_builtins[] = {
+
	{
+
		.pi_name = "rsa",
+
		.pi_ops = &pkgsign_ossl,
+
	},
+
};
+

+
static int
+
pkgsign_new(const char *name, struct pkgsign_ctx **ctx)
+
{
+
	struct pkgsign_impl *impl;
+
	const struct pkgsign_ops *ops;
+
	struct pkgsign_ctx *nctx;
+
	size_t ctx_size;
+
	int ret;
+

+
	assert(*ctx == NULL);
+

+
	ops = NULL;
+
	for (size_t i = 0; i < nitems(pkgsign_builtins); i++) {
+
		impl = &pkgsign_builtins[i];
+
		if (strcmp(name, impl->pi_name) == 0) {
+
			ops = impl->pi_ops;
+
			break;
+
		}
+
	}
+

+
	if (ops == NULL)
+
		return (EPKG_FATAL);
+

+
	ctx_size = ops->pkgsign_ctx_size;
+
	assert(ctx_size == 0 || ctx_size >= sizeof(struct pkgsign_ctx));
+
	if (ctx_size == 0)
+
		ctx_size = sizeof(struct pkgsign_ctx);
+

+
	nctx = xcalloc(1, ctx_size);
+
	nctx->impl = impl;
+

+
	ret = EPKG_OK;
+
	if (ops->pkgsign_new != NULL)
+
		ret = (*ops->pkgsign_new)(name, nctx);
+

+
	if (ret != EPKG_OK) {
+
		free(nctx);
+
		return (ret);
+
	}
+

+
	impl->pi_refs++;
+
	*ctx = nctx;
+
	return (EPKG_OK);
+
}
+

+
int
+
pkgsign_new_verify(const char *name, const struct pkgsign_ctx **octx)
+
{
+
	struct pkgsign_ctx *ctx;
+
	pkghash_entry *entry;
+
	int ret;
+

+
	entry = pkghash_get(pkgsign_verifiers, name);
+
	if (entry != NULL) {
+
		*octx = entry->value;
+
		return (EPKG_OK);
+
	}
+

+
	ctx = NULL;
+
	if ((ret = pkgsign_new(name, &ctx)) != EPKG_OK)
+
		return (ret);
+

+
	pkghash_safe_add(pkgsign_verifiers, name, ctx, NULL);
+
	*octx = ctx;
+
	return (EPKG_OK);
+
}
+

+
int
+
pkgsign_new_sign(const char *name, struct pkgsign_ctx **ctx)
+
{
+

+
	return (pkgsign_new(name, ctx));
+
}
+

+
void
+
pkgsign_set(struct pkgsign_ctx *sctx, pkg_password_cb *cb, const char *keyfile)
+
{
+

+
	sctx->pw_cb = cb;
+
	sctx->path = keyfile;
+
}
+

+
void
+
pkgsign_free(struct pkgsign_ctx *ctx)
+
{
+
	struct pkgsign_impl *impl;
+
	const struct pkgsign_ops *ops;
+

+
	if (ctx == NULL)
+
		return;
+
	impl = ctx->impl;
+
	ops = impl->pi_ops;
+
	if (ops->pkgsign_free != NULL)
+
		(*ops->pkgsign_free)(ctx);
+

+
	impl->pi_refs--;
+
	free(ctx);
+
}
+

+
int
+
pkgsign_sign(struct pkgsign_ctx *ctx, const char *path, unsigned char **sigret,
+
    size_t *siglen)
+
{
+

+
	return (*ctx->impl->pi_ops->pkgsign_sign)(ctx, path, sigret, siglen);
+
}
+

+
int
+
pkgsign_verify(const struct pkgsign_ctx *ctx, const char *key,
+
    unsigned char *sig, size_t siglen, int fd)
+
{
+

+
	return (*ctx->impl->pi_ops->pkgsign_verify)(ctx, key, sig, siglen, fd);
+
}
+

+
int
+
pkgsign_verify_cert(const struct pkgsign_ctx *ctx, unsigned char *key, size_t keylen,
+
    unsigned char *sig, size_t siglen, int fd)
+
{
+

+
	return (*ctx->impl->pi_ops->pkgsign_verify_cert)(ctx, key, keylen, sig,
+
	    siglen, fd);
+
}
+

+
const char *
+
pkgsign_impl_name(const struct pkgsign_ctx *ctx)
+
{
+

+
	return (ctx->impl->pi_name);
+
}
added libpkg/pkgsign_ossl.c
@@ -0,0 +1,509 @@
+
/*-
+
 * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
+
 * 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
+
 *    in this position and unchanged.
+
 * 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(S) ``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(S) 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 <sys/stat.h>
+
#include <sys/param.h>
+

+
#include <fcntl.h>
+

+
#include <openssl/err.h>
+
#include <openssl/ssl.h>
+

+
#include "pkg.h"
+
#include "private/event.h"
+
#include "private/pkg.h"
+
#include "private/pkgsign.h"
+

+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+
/*
+
 * This matches the historical usage for pkg.  Older versions sign the hex
+
 * encoding of the SHA256 checksum.  If we ever deprecated RSA, this can go
+
 * away.
+
 */
+
static EVP_MD *md_pkg_sha1;
+

+
static EVP_MD *
+
EVP_md_pkg_sha1(void)
+
{
+

+
	if (md_pkg_sha1 != NULL)
+
		return (md_pkg_sha1);
+

+
	md_pkg_sha1 = EVP_MD_meth_dup(EVP_sha1());
+
	if (md_pkg_sha1 == NULL)
+
		return (NULL);
+

+
	EVP_MD_meth_set_result_size(md_pkg_sha1,
+
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX));
+
	return (md_pkg_sha1);
+
}
+
#endif	/* OPENSSL_VERSION_NUMBER >= 0x10100000L */
+

+
struct ossl_sign_ctx {
+
	struct pkgsign_ctx sctx;
+
	EVP_PKEY *key;
+
};
+

+
/* Grab the ossl context from a pkgsign_ctx. */
+
#define	OSSL_CTX(c)	((struct ossl_sign_ctx *)(c))
+

+
static int
+
_load_private_key(struct ossl_sign_ctx *keyinfo)
+
{
+
	FILE *fp;
+

+
	if ((fp = fopen(keyinfo->sctx.path, "re")) == NULL)
+
		return (EPKG_FATAL);
+

+
	keyinfo->key = PEM_read_PrivateKey(fp, 0, keyinfo->sctx.pw_cb,
+
	    keyinfo->sctx.path);
+
	if (keyinfo->key == NULL) {
+
		fclose(fp);
+
		return (EPKG_FATAL);
+
	}
+

+
	fclose(fp);
+
	return (EPKG_OK);
+
}
+

+
static EVP_PKEY *
+
_load_public_key_buf(unsigned char *cert, int certlen)
+
{
+
	EVP_PKEY *pkey;
+
	BIO *bp;
+
	char errbuf[1024];
+

+
	bp = BIO_new_mem_buf((void *)cert, certlen);
+
	if (bp == NULL) {
+
		pkg_emit_error("error allocating public key bio: %s",
+
		    ERR_error_string(ERR_get_error(), errbuf));
+
		return (NULL);
+
	}
+

+
	pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL);
+
	if (pkey == NULL) {
+
		pkg_emit_error("error reading public key: %s",
+
		    ERR_error_string(ERR_get_error(), errbuf));
+
		BIO_free(bp);
+
		return (NULL);
+
	}
+

+
	BIO_free(bp);
+
	return (pkey);
+
}
+

+
struct ossl_verify_cbdata {
+
	unsigned char *key;
+
	size_t keylen;
+
	unsigned char *sig;
+
	size_t siglen;
+
	bool verbose;
+
};
+

+
static int
+
ossl_verify_cert_cb(int fd, void *ud)
+
{
+
	struct ossl_verify_cbdata *cbdata = ud;
+
	char *sha256;
+
	char *hash;
+
	char errbuf[1024];
+
	EVP_PKEY *pkey = NULL;
+
	EVP_PKEY_CTX *ctx;
+
	int ret;
+

+
	sha256 = pkg_checksum_fd(fd, PKG_HASH_TYPE_SHA256_HEX);
+
	if (sha256 == NULL)
+
		return (EPKG_FATAL);
+

+
	hash = pkg_checksum_data(sha256, strlen(sha256),
+
	    PKG_HASH_TYPE_SHA256_RAW);
+
	free(sha256);
+

+
	pkey = _load_public_key_buf(cbdata->key, cbdata->keylen);
+
	if (pkey == NULL) {
+
		free(hash);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
+
		EVP_PKEY_free(pkey);
+
		free(hash);
+
		return (EPKG_FATAL);
+
	}
+

+
	ctx = EVP_PKEY_CTX_new(pkey, NULL);
+
	if (ctx == NULL) {
+
		EVP_PKEY_free(pkey);
+
		free(hash);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_verify_init(ctx) <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		EVP_PKEY_free(pkey);
+
		free(hash);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		EVP_PKEY_free(pkey);
+
		free(hash);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		EVP_PKEY_free(pkey);
+
		free(hash);
+
		return (EPKG_FATAL);
+
	}
+

+
	ret = EVP_PKEY_verify(ctx, cbdata->sig, cbdata->siglen, hash,
+
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_RAW));
+
	free(hash);
+
	if (ret <= 0 && cbdata->verbose) {
+
		if (ret < 0)
+
			pkg_emit_error("rsa verify failed: %s",
+
					ERR_error_string(ERR_get_error(), errbuf));
+
		else
+
			pkg_emit_error("rsa signature verification failure");
+
	}
+
	if (ret <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		EVP_PKEY_free(pkey);
+
		return (EPKG_FATAL);
+
	}
+

+
	EVP_PKEY_CTX_free(ctx);
+
	EVP_PKEY_free(pkey);
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ossl_verify_cert(const struct pkgsign_ctx *sctx __unused, unsigned char *key,
+
    size_t keylen, unsigned char *sig, size_t siglen, int fd)
+
{
+
	int ret;
+
	bool need_close = false;
+
	struct ossl_verify_cbdata cbdata;
+

+
	(void)lseek(fd, 0, SEEK_SET);
+

+
	cbdata.key = key;
+
	cbdata.keylen = keylen;
+
	cbdata.sig = sig;
+
	cbdata.siglen = siglen;
+
	cbdata.verbose = true;
+

+
	SSL_load_error_strings();
+
	OpenSSL_add_all_algorithms();
+
	OpenSSL_add_all_ciphers();
+

+
	ret = pkg_emit_sandbox_call(ossl_verify_cert_cb, fd, &cbdata);
+
	if (need_close)
+
		close(fd);
+

+
	return (ret);
+
}
+

+
static int
+
ossl_verify_cb(int fd, void *ud)
+
{
+
	struct ossl_verify_cbdata *cbdata = ud;
+
	char *sha256;
+
	char errbuf[1024];
+
	EVP_PKEY *pkey = NULL;
+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+
	EVP_PKEY_CTX *ctx;
+
#else
+
	RSA *rsa;
+
#endif
+
	int ret;
+

+
	sha256 = pkg_checksum_fd(fd, PKG_HASH_TYPE_SHA256_HEX);
+
	if (sha256 == NULL)
+
		return (EPKG_FATAL);
+

+
	pkey = _load_public_key_buf(cbdata->key, cbdata->keylen);
+
	if (pkey == NULL) {
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
+
		EVP_PKEY_free(pkey);
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+
	ctx = EVP_PKEY_CTX_new(pkey, NULL);
+
	if (ctx == NULL) {
+
		EVP_PKEY_free(pkey);
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_verify_init(ctx) <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		EVP_PKEY_free(pkey);
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		EVP_PKEY_free(pkey);
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_md_pkg_sha1()) <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		EVP_PKEY_free(pkey);
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
	ret = EVP_PKEY_verify(ctx, cbdata->sig, cbdata->siglen, sha256,
+
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX));
+
#else
+
	rsa = EVP_PKEY_get1_RSA(pkey);
+

+
	ret = RSA_verify(NID_sha1, sha256,
+
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX), cbdata->sig,
+
	    cbdata->siglen, rsa);
+
#endif
+
	free(sha256);
+
	if (ret <= 0) {
+
		if (ret < 0)
+
			pkg_emit_error("%s: %s", cbdata->key,
+
				ERR_error_string(ERR_get_error(), errbuf));
+
		else
+
			pkg_emit_error("%s: rsa signature verification failure",
+
			    cbdata->key);
+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+
		EVP_PKEY_CTX_free(ctx);
+
#else
+
		RSA_free(rsa);
+
#endif
+
		EVP_PKEY_free(pkey);
+
		return (EPKG_FATAL);
+
	}
+

+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+
	EVP_PKEY_CTX_free(ctx);
+
#else
+
	RSA_free(rsa);
+
#endif
+
	EVP_PKEY_free(pkey);
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ossl_verify(const struct pkgsign_ctx *sctx __unused, const char *keypath,
+
    unsigned char *sig, size_t sig_len, int fd)
+
{
+
	int ret;
+
	bool need_close = false;
+
	struct ossl_verify_cbdata cbdata;
+
	char *key_buf;
+
	off_t key_len;
+

+
	if (file_to_buffer(keypath, (char**)&key_buf, &key_len) != EPKG_OK) {
+
		pkg_emit_errno("ossl_verify", "cannot read key");
+
		return (EPKG_FATAL);
+
	}
+

+
	(void)lseek(fd, 0, SEEK_SET);
+

+
	cbdata.key = key_buf;
+
	cbdata.keylen = key_len;
+
	cbdata.sig = sig;
+
	cbdata.siglen = sig_len;
+
	cbdata.verbose = false;
+

+
	SSL_load_error_strings();
+
	OpenSSL_add_all_algorithms();
+
	OpenSSL_add_all_ciphers();
+

+
	ret = pkg_emit_sandbox_call(ossl_verify_cert_cb, fd, &cbdata);
+
	if (need_close)
+
		close(fd);
+
	if (ret != EPKG_OK) {
+
		cbdata.verbose = true;
+
		(void)lseek(fd, 0, SEEK_SET);
+
		ret = pkg_emit_sandbox_call(ossl_verify_cb, fd, &cbdata);
+
	}
+

+
	free(key_buf);
+

+
	return (ret);
+
}
+

+
int
+
ossl_sign(struct pkgsign_ctx *sctx, const char *path, unsigned char **sigret,
+
    size_t *siglen)
+
{
+
	char errbuf[1024];
+
	struct ossl_sign_ctx *keyinfo = OSSL_CTX(sctx);
+
	int max_len = 0, ret;
+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+
	EVP_PKEY_CTX *ctx;
+
	const EVP_MD *md;
+

+
#if OPENSSL_VERSION_NUMBER < 0x30000000L
+
	md = EVP_md_pkg_sha1();
+
#else
+
	md = EVP_sha256();
+
	char *hash;
+
#endif
+
#else
+
	RSA *rsa;
+
#endif
+
	char *sha256;
+

+
	if (access(keyinfo->sctx.path, R_OK) == -1) {
+
		pkg_emit_errno("access", keyinfo->sctx.path);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (keyinfo->key == NULL && _load_private_key(keyinfo) != EPKG_OK) {
+
		pkg_emit_error("can't load key from %s", keyinfo->sctx.path);
+
		return (EPKG_FATAL);
+
	}
+

+
	max_len = EVP_PKEY_size(keyinfo->key);
+
	*sigret = xcalloc(1, max_len + 1);
+

+
	sha256 = pkg_checksum_file(path, PKG_HASH_TYPE_SHA256_HEX);
+
	if (sha256 == NULL)
+
		return (EPKG_FATAL);
+

+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+

+
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
	hash = pkg_checksum_data(sha256, strlen(sha256),
+
	    PKG_HASH_TYPE_SHA256_RAW);
+
#endif
+
	ctx = EVP_PKEY_CTX_new(keyinfo->key, NULL);
+
	if (ctx == NULL) {
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_sign_init(ctx) <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
+
		EVP_PKEY_CTX_free(ctx);
+
		free(sha256);
+
		return (EPKG_FATAL);
+
	}
+

+
	*siglen = max_len;
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
	ret = EVP_PKEY_sign(ctx, *sigret, siglen, hash,
+
	    EVP_MD_size(md));
+
#else
+
	ret = EVP_PKEY_sign(ctx, *sigret, siglen, sha256,
+
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX));
+
#endif
+

+
#else
+
	rsa = EVP_PKEY_get1_RSA(keyinfo->key);
+

+
	ret = RSA_sign(NID_sha1, sha256,
+
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX),
+
	    *sigret, siglen, rsa);
+
#endif
+
	free(sha256);
+
	if (ret <= 0) {
+
		pkg_emit_error("%s: %s", keyinfo->sctx.path,
+
		   ERR_error_string(ERR_get_error(), errbuf));
+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+
		EVP_PKEY_CTX_free(ctx);
+
#else
+
		RSA_free(rsa);
+
#endif
+
		return (EPKG_FATAL);
+
	}
+

+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+
	assert(*siglen <= INT_MAX);
+
	EVP_PKEY_CTX_free(ctx);
+
#else
+
	RSA_free(rsa);
+
#endif
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ossl_new(const char *name __unused, struct pkgsign_ctx *sctx __unused)
+
{
+

+
	SSL_load_error_strings();
+

+
	OpenSSL_add_all_algorithms();
+
	OpenSSL_add_all_ciphers();
+

+
	return (0);
+
}
+

+
static void
+
ossl_free(struct pkgsign_ctx *sctx)
+
{
+
	struct ossl_sign_ctx *keyinfo = OSSL_CTX(sctx);
+

+
	if (keyinfo->key != NULL)
+
		EVP_PKEY_free(keyinfo->key);
+

+
	ERR_free_strings();
+
}
+

+
const struct pkgsign_ops pkgsign_ossl = {
+
	.pkgsign_ctx_size = sizeof(struct ossl_sign_ctx),
+
	.pkgsign_new = ossl_new,
+
	.pkgsign_free = ossl_free,
+

+
	.pkgsign_sign = ossl_sign,
+
	.pkgsign_verify = ossl_verify,
+
	.pkgsign_verify_cert = ossl_verify_cert,
+
};
added libpkg/private/pkgsign.h
@@ -0,0 +1,101 @@
+
/*-
+
 * Copyright (c) 2021 Kyle Evans <kevans@FreeBSD.org>
+
 *
+
 * 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
+
 *    in this position and unchanged.
+
 * 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(S) ``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(S) 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 _PKGSIGN_H
+
#define _PKGSIGN_H
+

+
#include <pkg.h>
+

+
struct pkgsign_ctx;
+
struct pkgsign_ops;
+
struct pkgsign_impl;
+

+
/*
+
 * This should be embedded at the beginning of your pkgsign implementation's
+
 * context as needed.
+
 */
+
struct pkgsign_ctx {
+
	struct pkgsign_impl		*impl;
+
	pkg_password_cb			*pw_cb;
+
	const char			*path;
+
};
+

+
/* pkgsign request initialization/finalization. */
+
typedef int pkgsign_new_cb(const char *, struct pkgsign_ctx *);
+
typedef void pkgsign_free_cb(struct pkgsign_ctx *);
+

+
/* Sign (pkg_checksum), pass back signature and signature length. */
+
typedef int pkgsign_sign_cb(struct pkgsign_ctx *, const char *,
+
    unsigned char **, size_t *);
+

+
/* Validate the checksum against the expected signature. */
+
typedef int pkgsign_verify_cb(const struct pkgsign_ctx *, const char *,
+
    unsigned char *, size_t, int);
+

+
/*
+
 * Validate the checksum against the fingerprint's expected signature.  This
+
 * differs from the above for historical reasons, so it is both acceptable and
+
 * expected for them to be one and the same implementation.
+
 *
+
 * The longer explanation is that pkg historically signed the ShA256 hash of
+
 * a repo's contents as if it were SHA1, rather than SHA256.  This is largely
+
 * irrelevant, except that it's not interoperable with other implementations
+
 * that want to reproduce pkg's results because the hash function is physically
+
 * embedded in the resulting signature.
+
 */
+
typedef int pkgsign_verify_cert_cb(const struct pkgsign_ctx *, unsigned char *,
+
    size_t, unsigned char *, size_t, int);
+

+
struct pkgsign_ops {
+
	/*
+
	 * pkgsign_ctx_size <= sizeof(pkgsign_ctx) is wrong, but
+
	 * pkgsign_ctx_size == 0 will allocate just a pkgsign_ctx.
+
	 */
+
	size_t				 pkgsign_ctx_size;
+

+
	/* Optional request initialization/finalization handlers. */
+
	pkgsign_new_cb			*pkgsign_new;
+
	pkgsign_free_cb			*pkgsign_free;
+

+
	/* Non-optional. */
+
	pkgsign_sign_cb			*pkgsign_sign;
+

+
	/* Non-optional, and may be the same function. */
+
	pkgsign_verify_cb		*pkgsign_verify;
+
	pkgsign_verify_cert_cb		*pkgsign_verify_cert;
+
};
+

+
int pkgsign_new_sign(const char *, struct pkgsign_ctx **);
+
int pkgsign_new_verify(const char *, const struct pkgsign_ctx **);
+
void pkgsign_set(struct pkgsign_ctx *, pkg_password_cb *, const char *);
+
void pkgsign_free(struct pkgsign_ctx *);
+

+
int pkgsign_sign(struct pkgsign_ctx *, const char *, unsigned char **, size_t *);
+
int pkgsign_verify(const struct pkgsign_ctx *, const char *, unsigned char *,
+
    size_t, int);
+
int pkgsign_verify_cert(const struct pkgsign_ctx *, unsigned char *, size_t,
+
    unsigned char *, size_t, int);
+

+
#endif
modified libpkg/private/utils.h
@@ -78,8 +78,6 @@ struct dns_srvinfo {
	struct dns_srvinfo *next;
};

-
struct pkg_key;
-

int file_to_buffer(const char *, char **, off_t *);
int file_to_bufferat(int, const char *, char **, off_t *);
int format_exec_cmd(char **, const char *, const char *, const char *, const char *,
@@ -87,14 +85,6 @@ int format_exec_cmd(char **, const char *, const char *, const char *, const cha
int is_dir(const char *);
int is_link(const char *);

-
int rsa_new(struct pkg_key **, pkg_password_cb *, char *path);
-
void rsa_free(struct pkg_key *);
-
int rsa_sign(const char *path, struct pkg_key *keyinfo, unsigned char **sigret,
-
    unsigned int *siglen);
-
int rsa_verify(const char *key, unsigned char *sig, unsigned int sig_len, int fd);
-
int rsa_verify_cert(unsigned char *cert,
-
    int certlen, unsigned char *sig, int sig_len, int fd);
-

bool check_for_hardlink(hardlinks_t *hl, struct stat *st);
bool is_valid_abi(const char *arch, bool emit_error);
bool is_valid_os_version(struct pkg *pkg);
deleted libpkg/rsa.c
@@ -1,503 +0,0 @@
-
/*-
-
 * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
-
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
-
 * 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
-
 *    in this position and unchanged.
-
 * 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(S) ``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(S) 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 <sys/stat.h>
-
#include <sys/param.h>
-

-
#include <fcntl.h>
-

-
#include <openssl/err.h>
-
#include <openssl/ssl.h>
-

-
#include "pkg.h"
-
#include "private/event.h"
-
#include "private/pkg.h"
-

-
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-
/*
-
 * This matches the historical usage for pkg.  Older versions sign the hex
-
 * encoding of the SHA256 checksum.  If we ever deprecated RSA, this can go
-
 * away.
-
 */
-
static EVP_MD *md_pkg_sha1;
-

-
static EVP_MD *
-
EVP_md_pkg_sha1(void)
-
{
-

-
	if (md_pkg_sha1 != NULL)
-
		return (md_pkg_sha1);
-

-
	md_pkg_sha1 = EVP_MD_meth_dup(EVP_sha1());
-
	if (md_pkg_sha1 == NULL)
-
		return (NULL);
-

-
	EVP_MD_meth_set_result_size(md_pkg_sha1,
-
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX));
-
	return (md_pkg_sha1);
-
}
-
#endif	/* OPENSSL_VERSION_NUMBER >= 0x10100000L */
-

-
struct pkg_key {
-
	pkg_password_cb *pw_cb;
-
	char *path;
-
	EVP_PKEY *key;
-
};
-

-
static int
-
_load_private_key(struct pkg_key *keyinfo)
-
{
-
	FILE *fp;
-

-
	if ((fp = fopen(keyinfo->path, "re")) == NULL)
-
		return (EPKG_FATAL);
-

-
	keyinfo->key = PEM_read_PrivateKey(fp, 0, keyinfo->pw_cb, keyinfo->path);
-
	if (keyinfo->key == NULL) {
-
		fclose(fp);
-
		return (EPKG_FATAL);
-
	}
-

-
	fclose(fp);
-
	return (EPKG_OK);
-
}
-

-
static EVP_PKEY *
-
_load_public_key_buf(unsigned char *cert, int certlen)
-
{
-
	EVP_PKEY *pkey;
-
	BIO *bp;
-
	char errbuf[1024];
-

-
	bp = BIO_new_mem_buf((void *)cert, certlen);
-
	if (bp == NULL) {
-
		pkg_emit_error("error allocating public key bio: %s",
-
		    ERR_error_string(ERR_get_error(), errbuf));
-
		return (NULL);
-
	}
-

-
	pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL);
-
	if (pkey == NULL) {
-
		pkg_emit_error("error reading public key: %s",
-
		    ERR_error_string(ERR_get_error(), errbuf));
-
		BIO_free(bp);
-
		return (NULL);
-
	}
-

-
	BIO_free(bp);
-
	return (pkey);
-
}
-

-
struct rsa_verify_cbdata {
-
	unsigned char *key;
-
	size_t keylen;
-
	unsigned char *sig;
-
	size_t siglen;
-
	bool verbose;
-
};
-

-
static int
-
rsa_verify_cert_cb(int fd, void *ud)
-
{
-
	struct rsa_verify_cbdata *cbdata = ud;
-
	char *sha256;
-
	char *hash;
-
	char errbuf[1024];
-
	EVP_PKEY *pkey = NULL;
-
	EVP_PKEY_CTX *ctx;
-
	int ret;
-

-
	sha256 = pkg_checksum_fd(fd, PKG_HASH_TYPE_SHA256_HEX);
-
	if (sha256 == NULL)
-
		return (EPKG_FATAL);
-

-
	hash = pkg_checksum_data(sha256, strlen(sha256),
-
	    PKG_HASH_TYPE_SHA256_RAW);
-
	free(sha256);
-

-
	pkey = _load_public_key_buf(cbdata->key, cbdata->keylen);
-
	if (pkey == NULL) {
-
		free(hash);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
-
		EVP_PKEY_free(pkey);
-
		free(hash);
-
		return (EPKG_FATAL);
-
	}
-

-
	ctx = EVP_PKEY_CTX_new(pkey, NULL);
-
	if (ctx == NULL) {
-
		EVP_PKEY_free(pkey);
-
		free(hash);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_verify_init(ctx) <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		EVP_PKEY_free(pkey);
-
		free(hash);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		EVP_PKEY_free(pkey);
-
		free(hash);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		EVP_PKEY_free(pkey);
-
		free(hash);
-
		return (EPKG_FATAL);
-
	}
-

-
	ret = EVP_PKEY_verify(ctx, cbdata->sig, cbdata->siglen, hash,
-
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_RAW));
-
	free(hash);
-
	if (ret <= 0 && cbdata->verbose) {
-
		if (ret < 0)
-
			pkg_emit_error("rsa verify failed: %s",
-
					ERR_error_string(ERR_get_error(), errbuf));
-
		else
-
			pkg_emit_error("rsa signature verification failure");
-
	}
-
	if (ret <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		EVP_PKEY_free(pkey);
-
		return (EPKG_FATAL);
-
	}
-

-
	EVP_PKEY_CTX_free(ctx);
-
	EVP_PKEY_free(pkey);
-

-
	return (EPKG_OK);
-
}
-

-
int
-
rsa_verify_cert(unsigned char *key, int keylen,
-
    unsigned char *sig, int siglen, int fd)
-
{
-
	int ret;
-
	bool need_close = false;
-
	struct rsa_verify_cbdata cbdata;
-

-
	(void)lseek(fd, 0, SEEK_SET);
-

-
	cbdata.key = key;
-
	cbdata.keylen = keylen;
-
	cbdata.sig = sig;
-
	cbdata.siglen = siglen;
-
	cbdata.verbose = true;
-

-
	SSL_load_error_strings();
-
	OpenSSL_add_all_algorithms();
-
	OpenSSL_add_all_ciphers();
-

-
	ret = pkg_emit_sandbox_call(rsa_verify_cert_cb, fd, &cbdata);
-
	if (need_close)
-
		close(fd);
-

-
	return (ret);
-
}
-

-
static int
-
rsa_verify_cb(int fd, void *ud)
-
{
-
	struct rsa_verify_cbdata *cbdata = ud;
-
	char *sha256;
-
	char errbuf[1024];
-
	EVP_PKEY *pkey = NULL;
-
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-
	EVP_PKEY_CTX *ctx;
-
#else
-
	RSA *rsa;
-
#endif
-
	int ret;
-

-
	sha256 = pkg_checksum_fd(fd, PKG_HASH_TYPE_SHA256_HEX);
-
	if (sha256 == NULL)
-
		return (EPKG_FATAL);
-

-
	pkey = _load_public_key_buf(cbdata->key, cbdata->keylen);
-
	if (pkey == NULL) {
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
-
		EVP_PKEY_free(pkey);
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-
	ctx = EVP_PKEY_CTX_new(pkey, NULL);
-
	if (ctx == NULL) {
-
		EVP_PKEY_free(pkey);
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_verify_init(ctx) <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		EVP_PKEY_free(pkey);
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		EVP_PKEY_free(pkey);
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_md_pkg_sha1()) <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		EVP_PKEY_free(pkey);
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
	ret = EVP_PKEY_verify(ctx, cbdata->sig, cbdata->siglen, sha256,
-
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX));
-
#else
-
	rsa = EVP_PKEY_get1_RSA(pkey);
-

-
	ret = RSA_verify(NID_sha1, sha256,
-
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX), cbdata->sig,
-
	    cbdata->siglen, rsa);
-
#endif
-
	free(sha256);
-
	if (ret <= 0) {
-
		if (ret < 0)
-
			pkg_emit_error("%s: %s", cbdata->key,
-
				ERR_error_string(ERR_get_error(), errbuf));
-
		else
-
			pkg_emit_error("%s: rsa signature verification failure",
-
			    cbdata->key);
-
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-
		EVP_PKEY_CTX_free(ctx);
-
#else
-
		RSA_free(rsa);
-
#endif
-
		EVP_PKEY_free(pkey);
-
		return (EPKG_FATAL);
-
	}
-

-
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-
	EVP_PKEY_CTX_free(ctx);
-
#else
-
	RSA_free(rsa);
-
#endif
-
	EVP_PKEY_free(pkey);
-

-
	return (EPKG_OK);
-
}
-

-
int
-
rsa_verify(const char *key, unsigned char *sig, unsigned int sig_len, int fd)
-
{
-
	int ret;
-
	bool need_close = false;
-
	struct rsa_verify_cbdata cbdata;
-
	char *key_buf;
-
	off_t key_len;
-

-
	if (file_to_buffer(key, (char**)&key_buf, &key_len) != EPKG_OK) {
-
		pkg_emit_errno("rsa_verify", "cannot read key");
-
		return (EPKG_FATAL);
-
	}
-

-
	(void)lseek(fd, 0, SEEK_SET);
-

-
	cbdata.key = key_buf;
-
	cbdata.keylen = key_len;
-
	cbdata.sig = sig;
-
	cbdata.siglen = sig_len;
-
	cbdata.verbose = false;
-

-
	SSL_load_error_strings();
-
	OpenSSL_add_all_algorithms();
-
	OpenSSL_add_all_ciphers();
-

-
	ret = pkg_emit_sandbox_call(rsa_verify_cert_cb, fd, &cbdata);
-
	if (need_close)
-
		close(fd);
-
	if (ret != EPKG_OK) {
-
		cbdata.verbose = true;
-
		(void)lseek(fd, 0, SEEK_SET);
-
		ret = pkg_emit_sandbox_call(rsa_verify_cb, fd, &cbdata);
-
	}
-

-
	free(key_buf);
-

-
	return (ret);
-
}
-

-
int
-
rsa_sign(const char *path, struct pkg_key *keyinfo, unsigned char **sigret,
-
    unsigned int *osiglen)
-
{
-
	char errbuf[1024];
-
	int max_len = 0, ret;
-
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-
	EVP_PKEY_CTX *ctx;
-
	const EVP_MD *md;
-
	size_t siglen;
-

-
#if OPENSSL_VERSION_NUMBER < 0x30000000L
-
	md = EVP_md_pkg_sha1();
-
#else
-
	md = EVP_sha256();
-
	char *hash;
-
#endif
-
#else
-
	RSA *rsa;
-
#endif
-
	char *sha256;
-

-
	if (access(keyinfo->path, R_OK) == -1) {
-
		pkg_emit_errno("access", keyinfo->path);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (keyinfo->key == NULL && _load_private_key(keyinfo) != EPKG_OK) {
-
		pkg_emit_error("can't load key from %s", keyinfo->path);
-
		return (EPKG_FATAL);
-
	}
-

-
	max_len = EVP_PKEY_size(keyinfo->key);
-
	*sigret = xcalloc(1, max_len + 1);
-

-
	sha256 = pkg_checksum_file(path, PKG_HASH_TYPE_SHA256_HEX);
-
	if (sha256 == NULL)
-
		return (EPKG_FATAL);
-

-
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-

-
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
-
	hash = pkg_checksum_data(sha256, strlen(sha256),
-
	    PKG_HASH_TYPE_SHA256_RAW);
-
#endif
-
	ctx = EVP_PKEY_CTX_new(keyinfo->key, NULL);
-
	if (ctx == NULL) {
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_sign_init(ctx) <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
-
		EVP_PKEY_CTX_free(ctx);
-
		free(sha256);
-
		return (EPKG_FATAL);
-
	}
-

-
	siglen = max_len;
-
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
-
	ret = EVP_PKEY_sign(ctx, *sigret, &siglen, hash,
-
	    EVP_MD_size(md));
-
#else
-
	ret = EVP_PKEY_sign(ctx, *sigret, &siglen, sha256,
-
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX));
-
#endif
-

-
#else
-
	rsa = EVP_PKEY_get1_RSA(keyinfo->key);
-

-
	ret = RSA_sign(NID_sha1, sha256,
-
	    pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_HEX),
-
	    *sigret, osiglen, rsa);
-
#endif
-
	free(sha256);
-
	if (ret <= 0) {
-
		pkg_emit_error("%s: %s", keyinfo->path,
-
		   ERR_error_string(ERR_get_error(), errbuf));
-
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-
		EVP_PKEY_CTX_free(ctx);
-
#else
-
		RSA_free(rsa);
-
#endif
-
		return (EPKG_FATAL);
-
	}
-

-
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-
	assert(siglen <= INT_MAX);
-
	*osiglen = siglen;
-
	EVP_PKEY_CTX_free(ctx);
-
#else
-
	RSA_free(rsa);
-
#endif
-

-
	return (EPKG_OK);
-
}
-

-
int
-
rsa_new(struct pkg_key **keyinfo, pkg_password_cb *cb, char *path)
-
{
-
	assert(*keyinfo == NULL);
-

-
	*keyinfo = xcalloc(1, sizeof(struct pkg_key));
-
	(*keyinfo)->path = path;
-
	(*keyinfo)->pw_cb = cb;
-

-
	SSL_load_error_strings();
-

-
	OpenSSL_add_all_algorithms();
-
	OpenSSL_add_all_ciphers();
-

-
	return (EPKG_OK);
-
}
-

-
void
-
rsa_free(struct pkg_key *keyinfo)
-
{
-
	if (keyinfo == NULL)
-
		return;
-

-
	if (keyinfo->key != NULL)
-
		EVP_PKEY_free(keyinfo->key);
-

-
	free(keyinfo);
-
	ERR_free_strings();
-
}
-