Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
libpkg: add an ECC signer
Kyle Evans committed 2 years ago
commit 012369c0e9d52963393717d8b9bccf1d14230d1d
parent 4d68800
4 files changed +1295 -0
modified libpkg/Makefile.autosetup
@@ -8,6 +8,7 @@ SRCS= backup_lib.c \
	pkg.c \
	pkg_key.c \
	pkgsign.c \
+
	pkgsign_ecc.c \
	pkgsign_ossl.c \
	clean_cache.c \
	metalog.c \
@@ -64,6 +65,7 @@ LOCAL_CFLAGS= -I$(top_srcdir)/compat \
		-I$(top_srcdir)/external/curl/include \
		-I$(top_srcdir)/external/lua/src \
		-I$(top_srcdir)/external/liblua/ \
+
		-I$(top_srcdir)/external/libder/libder \
		-I$(top_srcdir)/external/libecc/include \
		-I$(top_srcdir)/libpkg/repo \
		-I$(top_builddir)/libpkg/repo \
@@ -103,6 +105,7 @@ STATIC_LIBS= @REPOS_STATIC_LIBS@ \
		$(top_builddir)/external/liblua/liblua.a \
		$(top_builddir)/compat/libbsd_compat.a \
		$(top_builddir)/external/libcurl/libcurl.a \
+
		$(top_builddir)/external/libder/libder.a \
		$(top_builddir)/external/libecc/libecc.a \
		lib$(LIB).a

modified libpkg/pkgsign.c
@@ -37,6 +37,7 @@

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

static pkghash *pkgsign_verifiers;

@@ -55,6 +56,18 @@ static struct pkgsign_impl {
		.pi_name = "rsa",
		.pi_ops = &pkgsign_ossl,
	},
+
	{
+
		.pi_name = "ecc",
+
		.pi_ops = &pkgsign_ecc,
+
	},
+
	{
+
		.pi_name = "ecdsa",
+
		.pi_ops = &pkgsign_ecc,
+
	},
+
	{
+
		.pi_name = "eddsa",
+
		.pi_ops = &pkgsign_ecc,
+
	},
};

static int
added libpkg/pkgsign_ecc.c
@@ -0,0 +1,1275 @@
+
/*-
+
 * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
+
 * All rights reserved.
+
 * 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/stat.h>
+
#include <sys/param.h>
+

+
#include <ctype.h>
+
#include <fcntl.h>
+

+
#include <libder.h>
+

+
#define	WITH_STDLIB
+
#include <libecc/libsig.h>
+
#undef WITH_STDLIB
+

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

+
struct ecc_sign_ctx {
+
	struct pkgsign_ctx	sctx;
+
	ec_params		params;
+
	ec_key_pair		keypair;
+
	ec_alg_type		sig_alg;
+
	hash_alg_type		sig_hash;
+
	bool			loaded;
+
};
+

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

+
#define PUBKEY_UNCOMPRESSED	0x04
+

+
#ifndef MAX
+
#define	MAX(a,b)	(((a)>(b))?(a):(b))
+
#endif
+

+
static const uint8_t oid_ecpubkey[] = \
+
    { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 };
+

+
static const uint8_t oid_secp[] = \
+
    { 0x2b, 0x81, 0x04, 0x00 };
+
static const uint8_t oid_secp256k1[] = \
+
    { 0x2b, 0x81, 0x04, 0x00, 0x0a };
+
static const uint8_t oid_brainpoolP[] = \
+
    { 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01 };
+

+
#define	ENTRY(name, params)	{ #name, sizeof(#name) - 1, params }
+
static const struct pkgkey_map_entry {
+
	const char		*name;
+
	size_t			 namesz;
+
	const ec_str_params	*params;
+
} pkgkey_map[] = {
+
	ENTRY(WEI25519, &wei25519_str_params),
+
	ENTRY(SECP256K1, &secp256k1_str_params),
+
	ENTRY(SECP384R1, &secp384r1_str_params),
+
	ENTRY(SECP512R1, &secp521r1_str_params),
+
	ENTRY(BRAINPOOLP256R1, &brainpoolp256r1_str_params),
+
	ENTRY(BRAINPOOLP256T1, &brainpoolp256t1_str_params),
+
	ENTRY(BRAINPOOLP320R1, &brainpoolp320r1_str_params),
+
	ENTRY(BRAINPOOLP320T1, &brainpoolp320t1_str_params),
+
	ENTRY(BRAINPOOLP384R1, &brainpoolp384r1_str_params),
+
	ENTRY(BRAINPOOLP384T1, &brainpoolp384t1_str_params),
+
	ENTRY(BRAINPOOLP512R1, &brainpoolp512r1_str_params),
+
	ENTRY(BRAINPOOLP512T1, &brainpoolp512t1_str_params),
+
};
+

+
static const char pkgkey_app[] = "pkg";
+
static const char pkgkey_signer[] = "ecc";
+

+
static const ec_str_params *
+
ecc_pkgkey_params(const uint8_t *curve, size_t curvesz)
+
{
+
	const struct pkgkey_map_entry *entry;
+

+
	for (size_t i = 0; i < NELEM(pkgkey_map); i++) {
+
		entry = &pkgkey_map[i];
+
		if (curvesz != entry->namesz)
+
			continue;
+
		if (memcmp(curve, entry->name, curvesz) == 0)
+
			return (entry->params);
+
	}
+

+
	return (NULL);
+
}
+

+
/*
+
 * PKCS#8 Key:
+
 *     PublicKeyInfo ::= SEQUENCE {
+
 *       algorithm   AlgorithmIdentifier,
+
 *       PublicKey   BIT STRING
+
 *     }
+
 *
+
 *     AlgorithmIdentifier ::= SEQUENCE {
+
 *       algorithm   OBJECT IDENTIFIER,
+
 *       parameters  ANY DEFINED BY algorithm OPTIONAL
+
 *      }
+
 *
+
 */
+
/* XXX Should eventually support other kinds of keys. */
+
static int
+
ecc_pubkey_write_pkcs8(const uint8_t *keydata, size_t keysz,
+
    uint8_t **buf, size_t *buflen)
+
{
+
	uint8_t keybuf[EC_PUB_KEY_MAX_SIZE + 2], *outbuf;
+
	struct libder_ctx *ctx;
+
	struct libder_object *keybits, *oid, *params, *root;
+
	int rc;
+
	bool ok;
+

+
	if (keysz > sizeof(keybuf) - 2)
+
		return (EPKG_FATAL);
+

+
	ctx = libder_open();
+
	if (ctx == NULL)
+
		return (EPKG_FATAL);
+

+
	rc = EPKG_FATAL;
+
	root = libder_obj_alloc_simple(ctx, BT_SEQUENCE, NULL, 0);
+
	if (root == NULL)
+
		goto out;
+

+
	params = libder_obj_alloc_simple(ctx, BT_SEQUENCE, NULL, 0);
+
	if (params == NULL)
+
		goto out;
+

+
	ok = libder_obj_append(root, params);
+
	assert(ok);
+

+
	/* id-ecPublicKey */
+
	oid = libder_obj_alloc_simple(ctx, BT_OID, oid_ecpubkey,
+
	    sizeof(oid_ecpubkey));
+
	if (oid == NULL)
+
		goto out;
+
	ok = libder_obj_append(params, oid);
+
	assert(ok);
+

+
	/*
+
	 * secp256k1, we should eventually allow other curves and actually
+
	 * construct the OID.
+
	 */
+
	oid = libder_obj_alloc_simple(ctx, BT_OID, oid_secp256k1,
+
	    sizeof(oid_secp256k1));
+
	if (oid == NULL)
+
		goto out;
+
	ok = libder_obj_append(params, oid);
+
	assert(ok);
+

+
	memset(keybuf, 0, sizeof(keybuf));
+
	keybuf[0] = 0;	/* No unused bits */
+
	keybuf[1] = PUBKEY_UNCOMPRESSED;
+
	memcpy(&keybuf[2], keydata, keysz);
+

+
	keybits = libder_obj_alloc_simple(ctx, BT_BITSTRING, &keybuf[0],
+
	    keysz + 2);
+
	if (keybits == NULL)
+
		goto out;
+
	ok = libder_obj_append(root, keybits);
+
	assert(ok);
+

+
	/* Finally, write it out. */
+
	*buflen = 0;
+
	outbuf = libder_write(ctx, root, NULL, buflen);
+
	if (outbuf != NULL) {
+
		*buf = outbuf;
+
		rc = EPKG_OK;
+
	}
+

+
out:
+
	libder_obj_free(root);
+
	libder_close(ctx);
+
	return (rc);
+
}
+

+
/*
+
 * pkg key (only for EdDSA):
+
 *     PkgPublicKeyInfo ::= SEQUENCE {
+
 *       Application UTF8String
+
 *       Version     INTEGER
+
 *       Signer      UTF8String
+
 *       KeyType     UTF8String
+
 *       Public      BOOLEAN
+
 *       Key         BIT STRING
+
 *     }
+
 *
+
 * "Application" will literally contain the string: "pkg"
+
 * "Version" must be 1
+
 * "Signer" must contain the part after "pkgsign_"
+
 * "KeyType" is signer-defined; for ECC, it must be the curve_name
+
 * "Public" is self-explanatory
+
 * "Key" is the key data itself, encoded as the PKCS#8 public key bit string
+
 *   with a lead byte indicating uncompressed (0x04)
+
 */
+
static int
+
ecc_write_pkgkey(const ec_params *params, uint8_t public,
+
    const uint8_t *keydata, size_t keysz, uint8_t **buf, size_t *buflen)
+
{
+
	uint8_t keybuf[MAX(EC_PRIV_KEY_MAX_SIZE, EC_PUB_KEY_MAX_SIZE) + 2];
+
	uint8_t *outbuf;
+
	struct libder_ctx *ctx;
+
	struct libder_object *keybits, *obj, *root;
+
	int rc;
+
	uint8_t version = 1;
+
	bool ok;
+

+
	if (keysz > sizeof(keybuf) - 2)
+
		return (EPKG_FATAL);
+

+
	ctx = libder_open();
+
	if (ctx == NULL)
+
		return (EPKG_FATAL);
+

+
	rc = EPKG_FATAL;
+
	root = libder_obj_alloc_simple(ctx, BT_SEQUENCE, NULL, 0);
+
	if (root == NULL)
+
		goto out;
+

+
	/* Application */
+
	obj = libder_obj_alloc_simple(ctx, BT_UTF8STRING, pkgkey_app,
+
	    sizeof(pkgkey_app) - 1);
+
	if (obj == NULL)
+
		goto out;
+
	ok = libder_obj_append(root, obj);
+
	assert(ok);
+

+
	/* Version */
+
	obj = libder_obj_alloc_simple(ctx, BT_INTEGER, &version, sizeof(version));
+
	if (obj == NULL)
+
		goto out;
+
	ok = libder_obj_append(root, obj);
+
	assert(ok);
+

+
	/* Signer */
+
	obj = libder_obj_alloc_simple(ctx, BT_UTF8STRING, pkgkey_signer,
+
	    sizeof(pkgkey_signer) - 1);
+
	if (obj == NULL)
+
		goto out;
+
	ok = libder_obj_append(root, obj);
+
	assert(ok);
+

+
	/* KeyType */
+
	obj = libder_obj_alloc_simple(ctx, BT_UTF8STRING, params->curve_name,
+
	    strlen(params->curve_name));
+
	if (obj == NULL)
+
		goto out;
+
	ok = libder_obj_append(root, obj);
+
	assert(ok);
+

+
	/* Public */
+
	obj = libder_obj_alloc_simple(ctx, BT_BOOLEAN, &public, sizeof(public));
+
	if (obj == NULL)
+
		goto out;
+
	ok = libder_obj_append(root, obj);
+
	assert(ok);
+

+
	memset(keybuf, 0, sizeof(keybuf));
+
	keybuf[0] = 0;	/* No unused bits */
+
	keybuf[1] = PUBKEY_UNCOMPRESSED;
+
	memcpy(&keybuf[2], keydata, keysz);
+

+
	keybits = libder_obj_alloc_simple(ctx, BT_BITSTRING, &keybuf[0],
+
	    keysz + 2);
+
	if (keybits == NULL)
+
		goto out;
+
	ok = libder_obj_append(root, keybits);
+
	assert(ok);
+

+
	/* Finally, write it out. */
+
	*buflen = 0;
+
	outbuf = libder_write(ctx, root, NULL, buflen);
+
	if (outbuf != NULL) {
+
		*buf = outbuf;
+
		rc = EPKG_OK;
+
	}
+

+
out:
+
	libder_obj_free(root);
+
	libder_close(ctx);
+
	return (rc);
+
}
+

+
static int
+
ecc_read_pkgkey(struct libder_object *root, ec_params *params, int public,
+
    uint8_t *rawkey, size_t *rawlen)
+
{
+
	struct libder_object *obj;
+
	const uint8_t *data;
+
	const ec_str_params *sparams;
+
	size_t datasz;
+
	int ret;
+

+
	if (libder_obj_type_simple(root) != BT_SEQUENCE)
+
		return (EPKG_FATAL);
+

+
	/* Application */
+
	obj = libder_obj_child(root, 0);
+
	if (obj == NULL || libder_obj_type_simple(obj) != BT_UTF8STRING)
+
		return (EPKG_FATAL);
+
	data = libder_obj_data(obj, &datasz);
+
	if (datasz != sizeof(pkgkey_app) - 1 ||
+
	    memcmp(data, pkgkey_app, datasz) != 0)
+
		return (EPKG_FATAL);
+

+
	/* Version */
+
	obj = libder_obj_child(root, 1);
+
	if (obj == NULL || libder_obj_type_simple(obj) != BT_INTEGER)
+
		return (EPKG_FATAL);
+
	data = libder_obj_data(obj, &datasz);
+
	if (datasz != 1 || *data != 1 /* XXX */)
+
		return (EPKG_FATAL);
+

+
	/* Signer */
+
	obj = libder_obj_child(root, 2);
+
	if (obj == NULL || libder_obj_type_simple(obj) != BT_UTF8STRING)
+
		return (EPKG_FATAL);
+
	data = libder_obj_data(obj, &datasz);
+
	if (datasz != sizeof(pkgkey_signer) - 1 ||
+
	    memcmp(data, pkgkey_signer, datasz) != 0)
+
		return (EPKG_FATAL);
+

+
	/* KeyType (curve) */
+
	obj = libder_obj_child(root, 3);
+
	if (obj == NULL || libder_obj_type_simple(obj) != BT_UTF8STRING)
+
		return (EPKG_FATAL);
+
	data = libder_obj_data(obj, &datasz);
+
	sparams = ecc_pkgkey_params(data, datasz);
+
	if (sparams == NULL)
+
		return (EPKG_FATAL);
+

+
	ret = import_params(params, sparams);
+
	if (ret != 0)
+
		return (EPKG_FATAL);
+

+
	/* Public? */
+
	obj = libder_obj_child(root, 4);
+
	if (obj == NULL || libder_obj_type_simple(obj) != BT_BOOLEAN)
+
		return (EPKG_FATAL);
+
	data = libder_obj_data(obj, &datasz);
+
	if (datasz != 1 || !data[0] != !public)
+
		return (EPKG_FATAL);
+

+
	/* Key */
+
	obj = libder_obj_child(root, 5);
+
	if (obj == NULL || libder_obj_type_simple(obj) != BT_BITSTRING)
+
		return (EPKG_FATAL);
+
	data = libder_obj_data(obj, &datasz);
+
	if (datasz <= 2 || data[0] != 0 || data[1] != PUBKEY_UNCOMPRESSED)
+
		return (EPKG_FATAL);
+

+
	data += 2;
+
	datasz -= 2;
+

+
	if (datasz > *rawlen)
+
		return (EPKG_FATAL);
+

+

+
	memcpy(rawkey, data, datasz);
+
	*rawlen = datasz;
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ecc_write_signature_component(struct libder_ctx *ctx, struct libder_object *root,
+
    const uint8_t *sigpart, size_t partlen)
+
{
+
	uint8_t sigbounce[EC_MAX_SIGLEN];
+
	struct libder_object *obj;
+
	size_t curlen;
+
	bool ok;
+

+
	/*
+
	 * If we need a leading 0 because the sign bit is set, we may need to
+
	 * bounce through sigbounce.  We may also need to bounce if there's some
+
	 * leading zeros.
+
	 */
+
	curlen = partlen;
+
	while (curlen > 0 && sigpart[0] == 0) {
+
		curlen--;
+
		sigpart++;
+
	}
+

+
	if ((sigpart[0] & 0x80) != 0) {
+
		/*
+
		 * If the high bit is set, we need to bounce it through
+
		 * sigbounce and insert a leading 0.
+
		 */
+
		sigbounce[0] = 0;
+
		memcpy(&sigbounce[1], sigpart, curlen);
+

+
		obj = libder_obj_alloc_simple(ctx, BT_INTEGER, sigbounce,
+
		    curlen + 1);
+
	} else {
+
		/*
+
		 * Otherwise, we can just leave it be.
+
		 */
+

+
		obj = libder_obj_alloc_simple(ctx, BT_INTEGER, sigpart, curlen);
+
	}
+

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

+
	ok = libder_obj_append(root, obj);
+
	assert(ok);
+
	return (EPKG_OK);
+
}
+

+
/*
+
 *       Ecdsa-Sig-Value  ::=  SEQUENCE  {
+
 *            r     INTEGER,
+
 *            s     INTEGER  }
+
 */
+
static int
+
ecc_write_signature(const uint8_t *sig, size_t siglen, uint8_t **sigret,
+
    size_t *sigretlen)
+
{
+
	struct libder_ctx *ctx;
+
	struct libder_object *obj, *root;
+
	uint8_t *outbuf;
+
	size_t complen;
+
	int rc;
+

+
	ctx = libder_open();
+
	if (ctx == NULL)
+
		return (EPKG_FATAL);
+

+
	rc = EPKG_FATAL;
+
	obj = NULL;
+
	root = libder_obj_alloc_simple(ctx, BT_SEQUENCE, NULL, 0);
+
	if (root == NULL)
+
		goto out;
+

+
	complen = siglen / 2;
+
	rc = ecc_write_signature_component(ctx, root, sig, complen);
+
	if (rc != EPKG_OK)
+
		goto out;
+

+
	sig += complen;
+
	siglen -= complen;
+
	rc = ecc_write_signature_component(ctx, root, sig, complen);
+
	if (rc != EPKG_OK)
+
		goto out;
+

+
	*sigretlen = 0;
+
	outbuf = libder_write(ctx, root, NULL, sigretlen);
+
	if (outbuf != NULL) {
+
		*sigret = outbuf;
+
		rc = EPKG_OK;
+
	}
+
out:
+
	libder_obj_free(obj);
+
	libder_close(ctx);
+
	return (rc);
+
}
+

+
static int
+
ecc_extract_signature(const uint8_t *sig, size_t siglen, uint8_t *rawsig,
+
    size_t rawlen)
+
{
+
	struct libder_ctx *ctx;
+
	struct libder_object *obj, *root;
+
	const uint8_t *sigdata;
+
	size_t compsz, datasz, sigoff;
+
	int rc;
+

+
	ctx = libder_open();
+
	if (ctx == NULL)
+
		return (EPKG_FATAL);
+

+
	rc = EPKG_FATAL;
+
	root = libder_read(ctx, sig, &siglen);
+
	if (root == NULL || libder_obj_type_simple(root) != BT_SEQUENCE)
+
		goto out;
+

+
	/* Descend into the sequence's payload, extract both numbers. */
+
	compsz = rawlen / 2;
+
	sigoff = 0;
+
	for (int i = 0; i < 2; i++) {
+
		obj = libder_obj_child(root, i);
+
		if (libder_obj_type_simple(obj) != BT_INTEGER)
+
			goto out;
+

+
		sigdata = libder_obj_data(obj, &datasz);
+
		if (datasz < 2 || datasz > compsz + 1)
+
			goto out;
+

+
		/*
+
		 * We may see an extra lead byte if our high bit of the first
+
		 * byte was set, since these numbers are positive by definition.
+
		 */
+
		if (sigdata[0] == 0 && (sigdata[1] & 0x80) != 0) {
+
			sigdata++;
+
			datasz--;
+
		}
+

+
		/* Sanity check: don't overflow the output. */
+
		if (sigoff + datasz > rawlen)
+
			goto out;
+

+
		/* Padding to the significant end if we're too small. */
+
		if (datasz < compsz) {
+
			memset(&rawsig[sigoff], 0, compsz - datasz);
+
			sigoff += compsz - datasz;
+
		}
+

+
		memcpy(&rawsig[sigoff], sigdata, datasz);
+
		sigoff += datasz;
+
	}
+

+
	/* Sanity check: must have exactly the required # of signature bits. */
+
	rc = (sigoff == rawlen) ? EPKG_OK : EPKG_FATAL;
+

+
out:
+
	libder_obj_free(root);
+
	libder_close(ctx);
+
	return (rc);
+
}
+

+
static int
+
ecc_extract_pubkey_string(const uint8_t *data, size_t datalen, uint8_t *rawkey,
+
    size_t *rawlen)
+
{
+
	uint8_t prefix, usebit;
+

+
	if (datalen <= 2)
+
		return (EPKG_FATAL);
+

+
	usebit = *data++;
+
	datalen--;
+

+
	if (usebit != 0)
+
		return (EPKG_FATAL);
+

+
	prefix = *data++;
+
	datalen--;
+

+
	if (prefix != PUBKEY_UNCOMPRESSED)
+
		return (EPKG_FATAL);
+

+
	if (datalen > *rawlen)
+
		return (EPKG_FATAL);
+

+
	memcpy(rawkey, data, datalen);
+
	*rawlen = datalen;
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ecc_extract_key_params(const uint8_t *oid, size_t oidlen,
+
    ec_params *rawparams)
+
{
+
	int ret;
+

+
	if (oidlen >= sizeof(oid_secp) &&
+
	    memcmp(oid, oid_secp, sizeof(oid_secp)) >= 0) {
+
		oid += sizeof(oid_secp);
+
		oidlen -= sizeof(oid_secp);
+

+
		if (oidlen != 1)
+
			return (EPKG_FATAL);
+

+
		ret = -1;
+
		switch (*oid) {
+
		case 0x0a:	/* secp256k1 */
+
			ret = import_params(rawparams, &secp256k1_str_params);
+
			break;
+
		case 0x22:	/* secp384r1 */
+
			ret = import_params(rawparams, &secp384r1_str_params);
+
			break;
+
		case 0x23:	/* secp521r1 */
+
			ret = import_params(rawparams, &secp521r1_str_params);
+
			break;
+
		default:
+
			return (EPKG_FATAL);
+
		}
+

+
		if (ret == 0)
+
			return (EPKG_OK);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (oidlen >= sizeof(oid_brainpoolP) &&
+
	    memcmp(oid, oid_brainpoolP, sizeof(oid_brainpoolP)) >= 0) {
+
		oid += sizeof(oid_brainpoolP);
+
		oidlen -= sizeof(oid_brainpoolP);
+

+
		if (oidlen != 1)
+
			return (EPKG_FATAL);
+

+
		ret = -1;
+
		switch (*oid) {
+
		case 0x07:	/* brainpoolP256r1 */
+
			ret = import_params(rawparams, &brainpoolp256r1_str_params);
+
			break;
+
		case 0x08:	/* brainpoolP256t1 */
+
			ret = import_params(rawparams, &brainpoolp256t1_str_params);
+
			break;
+
		case 0x09:	/* brainpoolP320r1 */
+
			ret = import_params(rawparams, &brainpoolp320r1_str_params);
+
			break;
+
		case 0x0a:	/* brainpoolP320t1 */
+
			ret = import_params(rawparams, &brainpoolp320t1_str_params);
+
			break;
+
		case 0x0b:	/* brainpoolP384r1 */
+
			ret = import_params(rawparams, &brainpoolp384r1_str_params);
+
			break;
+
		case 0x0c:	/* brainpoolP384t1 */
+
			ret = import_params(rawparams, &brainpoolp384t1_str_params);
+
			break;
+
		case 0x0d:	/* brainpoolP512r1 */
+
			ret = import_params(rawparams, &brainpoolp512r1_str_params);
+
			break;
+
		case 0x0e:	/* brainpoolP512t1 */
+
			ret = import_params(rawparams, &brainpoolp512t1_str_params);
+
			break;
+
		default:
+
			return (EPKG_FATAL);
+
		}
+

+
		if (ret == 0)
+
			return (EPKG_OK);
+
		return (EPKG_FATAL);
+
	}
+

+
#ifdef ECC_DEBUG
+
	for (size_t i = 0; i < oidlen; i++) {
+
		fprintf(stderr, "%.02x ", oid[i]);
+
	}
+

+
	fprintf(stderr, "\n");
+
#endif
+

+
	return (EPKG_FATAL);
+
}
+

+
/*
+
 * On entry, *rawparams should point to an ec_params that we can import the
+
 * key parameters to.  We'll either do that, or we'll set it to NULL if we could
+
 * not deduce the curve.
+
 */
+
static int
+
ecc_extract_pubkey(const uint8_t *key, size_t keylen, uint8_t *rawkey,
+
    size_t *rawlen, ec_params *rawparams)
+
{
+
	const uint8_t *oidp;
+
	struct libder_ctx *ctx;
+
	struct libder_object *keydata, *oid, *params, *root;
+
	size_t oidsz;
+
	int rc;
+

+
	ctx = libder_open();
+
	if (ctx == NULL)
+
		return (EPKG_FATAL);
+

+
	rc = EPKG_FATAL;
+
	root = libder_read(ctx, key, &keylen);
+
	if (root == NULL || libder_obj_type_simple(root) != BT_SEQUENCE)
+
		goto out;
+

+
	params = libder_obj_child(root, 0);
+

+
	if (params == NULL) {
+
		goto out;
+
	} else if (libder_obj_type_simple(params) != BT_SEQUENCE) {
+
		rc = ecc_read_pkgkey(root, rawparams, 1, rawkey, rawlen);
+
		goto out;
+
	}
+

+
	/* Is a sequence */
+
	keydata = libder_obj_child(root, 1);
+
	if (keydata == NULL || libder_obj_type_simple(keydata) != BT_BITSTRING)
+
		goto out;
+

+
	/* Key type */
+
	oid = libder_obj_child(params, 0);
+
	if (oid == NULL || libder_obj_type_simple(oid) != BT_OID)
+
		goto out;
+

+
	oidp = libder_obj_data(oid, &oidsz);
+
	if (oidsz != sizeof(oid_ecpubkey) ||
+
	    memcmp(oidp, oid_ecpubkey, oidsz) != 0)
+
		return (EPKG_FATAL);
+

+
	/* Curve */
+
	oid = libder_obj_child(params, 1);
+
	if (oid == NULL || libder_obj_type_simple(oid) != BT_OID)
+
		goto out;
+

+
	oidp = libder_obj_data(oid, &oidsz);
+
	if (ecc_extract_key_params(oidp, oidsz, rawparams) != EPKG_OK)
+
		goto out;
+

+
	/* Finally, peel off the key material */
+
	key = libder_obj_data(keydata, &keylen);
+
	if (ecc_extract_pubkey_string(key, keylen, rawkey, rawlen) != EPKG_OK)
+
		goto out;
+

+
	rc = EPKG_OK;
+
out:
+
	libder_obj_free(root);
+
	libder_close(ctx);
+
	return (rc);
+
}
+

+
static int
+
ecc_extract_privkey(const uint8_t *key, size_t keylen, uint8_t *rawkey,
+
    size_t *rawlen, ec_params *rawparams)
+
{
+
	const uint8_t *data;
+
	struct libder_ctx *ctx;
+
	struct libder_object *obj, *root;
+
	size_t datasz;
+
	int rc;
+

+
	ctx = libder_open();
+
	if (ctx == NULL)
+
		return (EPKG_FATAL);
+

+
	rc = EPKG_FATAL;
+
	root = libder_read(ctx, key, &keylen);
+
	if (root == NULL || libder_obj_type_simple(root) != BT_SEQUENCE)
+
		goto out;
+

+
	/* Sanity check the version, we're expecting version 1. */
+
	obj = libder_obj_child(root, 0);
+
	if (obj == NULL)
+
		goto out;
+
	if (libder_obj_type_simple(obj) != BT_INTEGER) {
+
		rc = ecc_read_pkgkey(root, rawparams, 0, rawkey, rawlen);
+
		goto out;
+
	}
+

+
	data = libder_obj_data(obj, &datasz);
+
	if (datasz != 1 || *data != 1)
+
		goto out;
+

+
	/* Grab the key data itself. */
+
	obj = libder_obj_child(root, 1);
+
	if (obj == NULL || libder_obj_type_simple(obj) != BT_OCTETSTRING)
+
		goto out;
+

+
	data = libder_obj_data(obj, &datasz);
+
	if (datasz == 0 || datasz > *rawlen)
+
		goto out;
+

+
	memcpy(rawkey, data, datasz);
+
	*rawlen = datasz;
+

+
	/* Next, extract the OID describing the key type. */
+
	obj = libder_obj_child(root, 2);
+
	if (obj == NULL || libder_obj_type_simple(obj) !=
+
	    ((BC_CONTEXT << 6) | BER_TYPE_CONSTRUCTED_MASK))
+
		goto out;
+

+
	obj = libder_obj_child(obj, 0);
+
	if (obj == NULL || libder_obj_type_simple(obj) != BT_OID)
+
		goto out;
+

+
	data = libder_obj_data(obj, &datasz);
+
	if (ecc_extract_key_params(data, datasz, rawparams) != EPKG_OK)
+
		goto out;
+

+
	rc = EPKG_OK;
+
out:
+
	libder_obj_free(root);
+
	libder_close(ctx);
+
	return (rc);
+
}
+

+
static int
+
_generate_private_key(struct ecc_sign_ctx *keyinfo)
+
{
+
	int ret;
+

+
	ret = ec_key_pair_gen(&keyinfo->keypair, &keyinfo->params,
+
	    keyinfo->sig_alg);
+

+
	if (ret != 0) {
+
		pkg_emit_error("failed to generate ecc keypair");
+
		return (EPKG_FATAL);
+
	}
+

+
	keyinfo->loaded = true;
+
	return (EPKG_OK);
+
}
+

+
static int
+
_load_private_key(struct ecc_sign_ctx *keyinfo)
+
{
+
	struct stat st;
+
	uint8_t keybuf[EC_PRIV_KEY_MAX_SIZE];
+
	uint8_t *filedata;
+
	ssize_t readsz;
+
	size_t keysz;
+
	int fd, rc, ret;
+
	size_t offset, resid;
+

+
	filedata = NULL;
+
	fd = -1;
+
	rc = EPKG_FATAL;
+

+
	keyinfo->loaded = false;
+
	if ((fd = open(keyinfo->sctx.path, O_RDONLY)) == -1)
+
		return (EPKG_FATAL);
+

+
	if (fstat(fd, &st) == -1)
+
		goto out;
+

+
	filedata = xmalloc(st.st_size);
+
	resid = st.st_size;
+
	offset = 0;
+
	while (resid != 0) {
+
		readsz = read(fd, &filedata[offset], resid);
+
		if (readsz <= 0)
+
			break;
+
		resid -= readsz;
+
		offset += readsz;
+
	}
+

+
	if (readsz < 0) {
+
		pkg_emit_errno("read", keyinfo->sctx.path);
+
		goto out;
+
	} else if (resid != 0) {
+
		pkg_emit_error("%s: failed to read key",
+
		    keyinfo->sctx.path);
+
		goto out;
+
	}
+

+
	/*
+
	 * Try DER-decoding it.  Unlike with loading a pubkey, anything
+
	 * requiring the privkey requires a new context for each operation, so
+
	 * we can just clobber keyinfo->params at will.
+
	 */
+
	keysz = sizeof(keybuf);
+
	if (ecc_extract_privkey(filedata, offset, keybuf, &keysz,
+
	    &keyinfo->params) != EPKG_OK) {
+
		pkg_emit_error("failed to decode private key");
+
		goto out;
+
	}
+

+
	ret = ec_priv_key_import_from_buf(&keyinfo->keypair.priv_key,
+
	    &keyinfo->params, keybuf, keysz, keyinfo->sig_alg);
+
	if (ret == 0) {
+
		ret = init_pubkey_from_privkey(&keyinfo->keypair.pub_key,
+
			&keyinfo->keypair.priv_key);
+
		if (ret == 0) {
+
			keyinfo->loaded = true;
+
			rc = EPKG_OK;
+
		} else {
+
			pkg_emit_error("%s: failed to derive public key",
+
			    keyinfo->sctx.path);
+
			rc = EPKG_FATAL;
+
		}
+
	} else {
+
		pkg_emit_error("%s: failed to import private key",
+
		    keyinfo->sctx.path);
+
		rc = EPKG_FATAL;
+
	}
+

+
out:
+
	free(filedata);
+
	if (fd != -1)
+
		close(fd);
+
	return (rc);
+
}
+

+
struct ecc_verify_cbdata {
+
	const struct pkgsign_ctx *sctx;
+
	unsigned char *key;
+
	size_t keylen;
+
	unsigned char *sig;
+
	size_t siglen;
+
};
+

+
static int
+
ecc_verify_internal(struct ecc_verify_cbdata *cbdata, const uint8_t *hash,
+
    size_t hashsz)
+
{
+
	ec_pub_key pubkey;
+
	ec_params derparams;
+
	struct ecc_sign_ctx *keyinfo = ECC_CTX(cbdata->sctx);
+
	uint8_t keybuf[EC_PUB_KEY_MAX_SIZE];
+
	uint8_t rawsig[EC_MAX_SIGLEN];
+
	size_t keysz;
+
	int ret;
+
	uint8_t ecsiglen;
+

+
	keysz = MIN(sizeof(keybuf), cbdata->keylen / 2);
+

+
	keysz = sizeof(keybuf);
+
	if (ecc_extract_pubkey(cbdata->key, cbdata->keylen, keybuf,
+
	    &keysz, &derparams) != EPKG_OK) {
+
		pkg_emit_error("failed to parse key");
+
		return (EPKG_FATAL);
+
	}
+

+
	ret = ec_get_sig_len(&derparams, keyinfo->sig_alg, keyinfo->sig_hash,
+
	    &ecsiglen);
+
	if (ret != 0)
+
		return (EPKG_FATAL);
+

+
	/*
+
	 * Signatures are DER-encoded, whether by OpenSSL or pkg.
+
	 */
+
	if (ecc_extract_signature(cbdata->sig, cbdata->siglen,
+
	    rawsig, ecsiglen) != EPKG_OK) {
+
		pkg_emit_error("failed to decode signature");
+
		return (EPKG_FATAL);
+
	}
+

+
	ret = ec_pub_key_import_from_aff_buf(&pubkey, &derparams,
+
	    keybuf, keysz, keyinfo->sig_alg);
+
	if (ret != 0) {
+
		pkg_emit_error("failed to import key");
+
		return (EPKG_FATAL);
+
	}
+

+
	ret = ec_verify(rawsig, ecsiglen, &pubkey, hash, hashsz, keyinfo->sig_alg,
+
	    keyinfo->sig_hash, NULL, 0);
+
	if (ret != 0) {
+
			if (cbdata->siglen < ecsiglen) {
+
				pkg_emit_error("yeah, actually invalid...");
+
				return (EPKG_FATAL);
+
			}
+
		pkg_emit_error("failed to verify signature");
+
		return (EPKG_FATAL);
+
	}
+

+
	if (cbdata->siglen < ecsiglen) {
+
		pkg_emit_error("told you so.");
+
		return (EPKG_FATAL);
+
	}
+

+
	return (EPKG_OK);
+
}
+

+

+
static int
+
ecc_verify_cert_cb(int fd, void *ud)
+
{
+
	struct ecc_verify_cbdata *cbdata = ud;
+
	char *sha256;
+
	int ret;
+

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

+
	ret = ecc_verify_internal(cbdata, sha256, strlen(sha256));
+
	if (ret != 0) {
+
		pkg_emit_error("ecc signature verification failure");
+
		return (EPKG_FATAL);
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ecc_verify_cert(const struct pkgsign_ctx *sctx, unsigned char *key,
+
    size_t keylen, unsigned char *sig, size_t siglen, int fd)
+
{
+
	int ret;
+
	struct ecc_verify_cbdata cbdata;
+

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

+
	cbdata.sctx = sctx;
+
	cbdata.key = key;
+
	cbdata.keylen = keylen;
+
	cbdata.sig = sig;
+
	cbdata.siglen = siglen;
+

+
	ret = pkg_emit_sandbox_call(ecc_verify_cert_cb, fd, &cbdata);
+

+
	return (ret);
+
}
+

+
static int
+
ecc_verify_cb(int fd, void *ud)
+
{
+
	struct ecc_verify_cbdata *cbdata = ud;
+
	uint8_t *blake2;
+
	int ret;
+

+
	blake2 = pkg_checksum_fd(fd, PKG_HASH_TYPE_BLAKE2_RAW);
+
	if (blake2 == NULL)
+
		return (EPKG_FATAL);
+

+
	ret = ecc_verify_internal(cbdata, blake2,
+
	    pkg_checksum_type_size(PKG_HASH_TYPE_BLAKE2_RAW));
+

+
	free(blake2);
+
	if (ret != 0) {
+
		pkg_emit_error("ecc signature verification failure");
+
		return (EPKG_FATAL);
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ecc_verify(const struct pkgsign_ctx *sctx, const char *keypath,
+
    unsigned char *sig, size_t sig_len, int fd)
+
{
+
	int ret;
+
	struct ecc_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("ecc_verify", "cannot read key");
+
		return (EPKG_FATAL);
+
	}
+

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

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

+
	ret = pkg_emit_sandbox_call(ecc_verify_cb, fd, &cbdata);
+

+
	free(key_buf);
+

+
	return (ret);
+
}
+

+
static int
+
ecc_sign_data(struct pkgsign_ctx *sctx, const unsigned char *msg, size_t msgsz,
+
    unsigned char **sigret, size_t *siglen)
+
{
+
	uint8_t rawsig[EC_MAX_SIGLEN];
+
	struct ecc_sign_ctx *keyinfo = ECC_CTX(sctx);
+
	int ret;
+
	uint8_t rawlen;
+

+
	if (!keyinfo->loaded && _load_private_key(keyinfo) != EPKG_OK) {
+
		pkg_emit_error("%s: failed to load key", keyinfo->sctx.path);
+
		return (EPKG_FATAL);
+
	}
+

+
	ret = ec_get_sig_len(&keyinfo->params, keyinfo->sig_alg, keyinfo->sig_hash,
+
		&rawlen);
+
	if (ret != 0)
+
		return (EPKG_FATAL);
+

+
	assert(rawlen <= sizeof(rawsig));
+

+
	assert(priv_key_check_initialized_and_type(&keyinfo->keypair.priv_key,
+
	    keyinfo->sig_alg) == 0);
+
	assert(pub_key_check_initialized_and_type(&keyinfo->keypair.pub_key,
+
	    keyinfo->sig_alg) == 0);
+

+
	ret = ec_sign(rawsig, rawlen, &keyinfo->keypair, msg, msgsz,
+
	    keyinfo->sig_alg, keyinfo->sig_hash, NULL, 0);
+

+
	if (ret != 0) {
+
		pkg_emit_error("%s: ecc signing failure", keyinfo->sctx.path);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (ecc_write_signature(rawsig, rawlen, sigret, siglen) != EPKG_OK) {
+
		pkg_emit_error("failed to encode signature");
+
		return (EPKG_FATAL);
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ecc_sign(struct pkgsign_ctx *sctx, const char *path, unsigned char **sigret,
+
    size_t *siglen)
+
{
+
	uint8_t *blake2;
+
	struct ecc_sign_ctx *keyinfo = ECC_CTX(sctx);
+
	int ret;
+

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

+
	blake2 = pkg_checksum_file(path, PKG_HASH_TYPE_BLAKE2_RAW);
+
	if (blake2 == NULL)
+
		return (EPKG_FATAL);
+

+
	ret = ecc_sign_data(sctx, blake2,
+
	    pkg_checksum_type_size(PKG_HASH_TYPE_BLAKE2_RAW), sigret, siglen);
+
	free(blake2);
+

+
	return (ret);
+
}
+

+
static int
+
ecc_generate(struct pkgsign_ctx *sctx, const struct iovec *iov __unused,
+
    int niov __unused)
+
{
+
	uint8_t keybuf[EC_PRIV_KEY_MAX_SIZE], *outbuf;
+
	struct ecc_sign_ctx *keyinfo = ECC_CTX(sctx);
+
	const char *path = sctx->path;
+
	FILE *fp;
+
	size_t keysz, outsz;
+

+
	if (niov != 0)
+
		return (EPKG_FATAL);
+

+
	if (_generate_private_key(keyinfo) != 0)
+
		return (EPKG_FATAL);
+

+
	assert(priv_key_check_initialized_and_type(&keyinfo->keypair.priv_key,
+
	    keyinfo->sig_alg) == 0);
+
	assert(pub_key_check_initialized_and_type(&keyinfo->keypair.pub_key,
+
	    keyinfo->sig_alg) == 0);
+

+
	keysz = EC_PRIV_KEY_EXPORT_SIZE(&keyinfo->keypair.priv_key);
+
	if (ec_priv_key_export_to_buf(&keyinfo->keypair.priv_key,
+
	    keybuf, keysz) != 0) {
+
		pkg_emit_error("failed to export ecc key");
+
		return (EPKG_FATAL);
+
	}
+

+
	outbuf = NULL;
+
	outsz = 0;
+
	if (ecc_write_pkgkey(&keyinfo->params, 0, keybuf, keysz, &outbuf,
+
	    &outsz) != EPKG_OK) {
+
		pkg_emit_error("%s: failed to write DER-encoded key",
+
		    sctx->path);
+
		return (EPKG_FATAL);
+
	}
+

+
	fp = fopen(path, "wb");
+
	if (fp == NULL) {
+
		pkg_emit_errno("fopen write", path);
+
		free(outbuf);
+
		return (EPKG_FATAL);
+
	}
+

+
	if (fchmod(fileno(fp), 0400) != 0) {
+
		pkg_emit_errno("fchmod", path);
+
		free(outbuf);
+
		fclose(fp);
+
		return (EPKG_FATAL);
+
	}
+

+
	fwrite(outbuf, outsz, 1, fp);
+
	free(outbuf);
+
	outbuf = NULL;
+
	if (ferror(fp) != 0 || fflush(fp) != 0) {
+
		pkg_emit_errno("fwrite", path);
+
		fclose(fp);
+
		return (EPKG_FATAL);
+
	}
+

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

+
static int
+
ecc_pubkey(struct pkgsign_ctx *sctx, char **pubkey, size_t *pubkeylen)
+
{
+
	struct ecc_sign_ctx *keyinfo = ECC_CTX(sctx);
+
	uint8_t keybuf[EC_PUB_KEY_MAX_SIZE];
+
	size_t keylen;
+
	int ret;
+

+
	if (!keyinfo->loaded && _load_private_key(keyinfo) != EPKG_OK) {
+
		pkg_emit_error("%s: failed to load key", sctx->path);
+
		return (EPKG_FATAL);
+
	}
+

+
	assert(keyinfo->loaded);
+
	assert(pub_key_check_initialized_and_type(&keyinfo->keypair.pub_key,
+
	    keyinfo->sig_alg) == 0);
+

+
	keylen = 2 * BYTECEIL(keyinfo->params.ec_fp.p_bitlen);
+
	ret = ec_pub_key_export_to_aff_buf(&keyinfo->keypair.pub_key, keybuf, keylen);
+
	if (ret != 0) {
+
		pkg_emit_error("%s: failed to export key", sctx->path);
+
		return (EPKG_FATAL);
+
	}
+

+
	/*
+
	 * We'll write a custom format for anything but ECDSA that includes our
+
	 * params wholesale so that we can just import them directly.
+
	 *
+
	 * ECDSA keys get exported as PKCS#8 for interoperability with OpenSSL.
+
	 */
+
	if (keyinfo->sig_alg != ECDSA) {
+
		if (ecc_write_pkgkey(&keyinfo->params, 1, keybuf, keylen,
+
		    (uint8_t **)pubkey, pubkeylen) != EPKG_OK) {
+
			pkg_emit_error("%s: failed to write DER-encoded key",
+

+
			    sctx->path);
+
			return (EPKG_FATAL);
+
		}
+
	} else if (ecc_pubkey_write_pkcs8(keybuf, keylen,
+
	    (uint8_t **)pubkey, pubkeylen) != EPKG_OK) {
+
		pkg_emit_error("%s: failed to write DER-encoded key", sctx->path);
+
		return (EPKG_FATAL);
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
ecc_new(const char *name __unused, struct pkgsign_ctx *sctx)
+
{
+
	struct ecc_sign_ctx *keyinfo = ECC_CTX(sctx);
+
	int ret;
+

+
	ret = EPKG_FATAL;
+
	if (strcmp(name, "ecc") == 0 || strcmp(name, "eddsa") == 0) {
+
			keyinfo->sig_alg = EDDSA25519;
+
			keyinfo->sig_hash = SHA512;
+
			ret = import_params(&keyinfo->params, &wei25519_str_params);
+
	} else if (strcmp(name, "ecdsa") == 0) {
+
			keyinfo->sig_alg = ECDSA;
+
			keyinfo->sig_hash = SHA256;
+
			ret = import_params(&keyinfo->params, &secp256k1_str_params);
+
	}
+

+
	if (ret != 0)
+
		return (EPKG_FATAL);
+

+
	return (0);
+
}
+

+
static void
+
ecc_free(struct pkgsign_ctx *sctx __unused)
+
{
+

+
}
+

+
const struct pkgsign_ops pkgsign_ecc = {
+
	.pkgsign_ctx_size = sizeof(struct ecc_sign_ctx),
+
	.pkgsign_new = ecc_new,
+
	.pkgsign_free = ecc_free,
+

+
	.pkgsign_sign = ecc_sign,
+
	.pkgsign_verify = ecc_verify,
+
	.pkgsign_verify_cert = ecc_verify_cert,
+

+
	.pkgsign_generate = ecc_generate,
+
	.pkgsign_pubkey = ecc_pubkey,
+
};
modified libpkg/private/pkgsign.h
@@ -26,6 +26,10 @@
#ifndef _PKGSIGN_H
#define _PKGSIGN_H

+
#ifdef HAVE_CONFIG_H
+
#include "pkg_config.h"
+
#endif
+

#include <pkg.h>

struct pkgsign_ctx;