Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153216399
D48108.id148010.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
D48108.id148010.diff
View Options
diff --git a/usr.sbin/pkg/Makefile b/usr.sbin/pkg/Makefile
--- a/usr.sbin/pkg/Makefile
+++ b/usr.sbin/pkg/Makefile
@@ -21,11 +21,14 @@
CONFSDIR= /etc/pkg
CONFSMODE= 644
PROG= pkg
-SRCS= pkg.c rsa.c dns_utils.c config.c hash.c
+SRCS= pkg.c rsa.c dns_utils.c config.c ecc.c hash.c
MAN= pkg.7
CFLAGS+=-I${SRCTOP}/contrib/libucl/include
.PATH: ${SRCTOP}/contrib/libucl/include
-LIBADD= archive fetch ucl crypto ssl util md
+LIBADD= archive der fetch pkgecc ucl crypto ssl util md
+
+CFLAGS+=-I${SRCTOP}/contrib/libder/libder
+CFLAGS+=-I${SRCTOP}/crypto/libecc/include
.include <bsd.prog.mk>
diff --git a/usr.sbin/pkg/ecc.c b/usr.sbin/pkg/ecc.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/pkg/ecc.c
@@ -0,0 +1,606 @@
+/*-
+ * 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 <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include <libder.h>
+
+#define WITH_STDLIB
+#include <libecc/libsig.h>
+#undef WITH_STDLIB
+
+#include "pkg.h"
+#include "hash.h"
+
+/* libpkg shim */
+#define STREQ(l, r) (strcmp(l, r) == 0)
+
+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_CCTX(c) ((const struct ecc_sign_ctx *)(c))
+#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 < nitems(pkgkey_map); i++) {
+ entry = &pkgkey_map[i];
+ if (curvesz != entry->namesz)
+ continue;
+ if (memcmp(curve, entry->name, curvesz) == 0)
+ return (entry->params);
+ }
+
+ return (NULL);
+}
+
+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 (1);
+
+ /* Application */
+ obj = libder_obj_child(root, 0);
+ if (obj == NULL || libder_obj_type_simple(obj) != BT_UTF8STRING)
+ return (1);
+ data = libder_obj_data(obj, &datasz);
+ if (datasz != sizeof(pkgkey_app) - 1 ||
+ memcmp(data, pkgkey_app, datasz) != 0)
+ return (1);
+
+ /* Version */
+ obj = libder_obj_child(root, 1);
+ if (obj == NULL || libder_obj_type_simple(obj) != BT_INTEGER)
+ return (1);
+ data = libder_obj_data(obj, &datasz);
+ if (datasz != 1 || *data != 1 /* XXX */)
+ return (1);
+
+ /* Signer */
+ obj = libder_obj_child(root, 2);
+ if (obj == NULL || libder_obj_type_simple(obj) != BT_UTF8STRING)
+ return (1);
+ data = libder_obj_data(obj, &datasz);
+ if (datasz != sizeof(pkgkey_signer) - 1 ||
+ memcmp(data, pkgkey_signer, datasz) != 0)
+ return (1);
+
+ /* KeyType (curve) */
+ obj = libder_obj_child(root, 3);
+ if (obj == NULL || libder_obj_type_simple(obj) != BT_UTF8STRING)
+ return (1);
+ data = libder_obj_data(obj, &datasz);
+ sparams = ecc_pkgkey_params(data, datasz);
+ if (sparams == NULL)
+ return (1);
+
+ ret = import_params(params, sparams);
+ if (ret != 0)
+ return (1);
+
+ /* Public? */
+ obj = libder_obj_child(root, 4);
+ if (obj == NULL || libder_obj_type_simple(obj) != BT_BOOLEAN)
+ return (1);
+ data = libder_obj_data(obj, &datasz);
+ if (datasz != 1 || !data[0] != !public)
+ return (1);
+
+ /* Key */
+ obj = libder_obj_child(root, 5);
+ if (obj == NULL || libder_obj_type_simple(obj) != BT_BITSTRING)
+ return (1);
+ data = libder_obj_data(obj, &datasz);
+ if (datasz <= 2 || data[0] != 0 || data[1] != PUBKEY_UNCOMPRESSED)
+ return (1);
+
+ data += 2;
+ datasz -= 2;
+
+ if (datasz > *rawlen)
+ return (1);
+
+
+ memcpy(rawkey, data, datasz);
+ *rawlen = datasz;
+
+ return (0);
+}
+
+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 (1);
+
+ rc = 1;
+ 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) ? 0 : 1;
+
+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 (1);
+
+ usebit = *data++;
+ datalen--;
+
+ if (usebit != 0)
+ return (1);
+
+ prefix = *data++;
+ datalen--;
+
+ if (prefix != PUBKEY_UNCOMPRESSED)
+ return (1);
+
+ if (datalen > *rawlen)
+ return (1);
+
+ memcpy(rawkey, data, datalen);
+ *rawlen = datalen;
+
+ return (0);
+}
+
+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 (1);
+
+ 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 (1);
+ }
+
+ if (ret == 0)
+ return (0);
+ return (1);
+ }
+
+ 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 (1);
+
+ 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 (1);
+ }
+
+ if (ret == 0)
+ return (0);
+ return (1);
+ }
+
+#ifdef ECC_DEBUG
+ for (size_t i = 0; i < oidlen; i++) {
+ fprintf(stderr, "%.02x ", oid[i]);
+ }
+
+ fprintf(stderr, "\n");
+#endif
+
+ return (1);
+}
+
+/*
+ * 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(FILE *keyfp, 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 (1);
+
+ rc = 1;
+ assert((keyfp != NULL) ^ (key != NULL));
+ if (keyfp != NULL) {
+ root = libder_read_file(ctx, keyfp, &keylen);
+ } else {
+ 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 (1);
+
+ /* 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) != 0)
+ goto out;
+
+ /* Finally, peel off the key material */
+ key = libder_obj_data(keydata, &keylen);
+ if (ecc_extract_pubkey_string(key, keylen, rawkey, rawlen) != 0)
+ goto out;
+
+ rc = 0;
+out:
+ libder_obj_free(root);
+ libder_close(ctx);
+ return (rc);
+}
+
+struct ecc_verify_cbdata {
+ const struct pkgsign_ctx *sctx;
+ FILE *keyfp;
+ const 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;
+ const struct ecc_sign_ctx *keyinfo = ECC_CCTX(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->keyfp, cbdata->key, cbdata->keylen,
+ keybuf, &keysz, &derparams) != 0) {
+ warnx("failed to parse key");
+ return (1);
+ }
+
+ ret = ec_get_sig_len(&derparams, keyinfo->sig_alg, keyinfo->sig_hash,
+ &ecsiglen);
+ if (ret != 0)
+ return (1);
+
+ /*
+ * Signatures are DER-encoded, whether by OpenSSL or pkg.
+ */
+ if (ecc_extract_signature(cbdata->sig, cbdata->siglen,
+ rawsig, ecsiglen) != 0) {
+ warnx("failed to decode signature");
+ return (1);
+ }
+
+ ret = ec_pub_key_import_from_aff_buf(&pubkey, &derparams,
+ keybuf, keysz, keyinfo->sig_alg);
+ if (ret != 0) {
+ warnx("failed to import key");
+ return (1);
+ }
+
+ ret = ec_verify(rawsig, ecsiglen, &pubkey, hash, hashsz, keyinfo->sig_alg,
+ keyinfo->sig_hash, NULL, 0);
+ if (ret != 0) {
+ warnx("failed to verify signature");
+ return (1);
+ }
+
+ return (0);
+}
+
+static bool
+ecc_verify_data(const struct pkgsign_ctx *sctx,
+ const char *data, size_t datasz, const char *sigfile,
+ const unsigned char *key, int keylen,
+ unsigned char *sig, int siglen)
+{
+ int ret;
+ struct ecc_verify_cbdata cbdata;
+
+ ret = 1;
+
+ if (sigfile != NULL) {
+ cbdata.keyfp = fopen(sigfile, "r");
+ if (cbdata.keyfp == NULL) {
+ warn("fopen: %s", sigfile);
+ return (false);
+ }
+ } else {
+ cbdata.keyfp = NULL;
+ cbdata.key = key;
+ cbdata.keylen = keylen;
+ }
+
+ cbdata.sctx = sctx;
+ cbdata.sig = sig;
+ cbdata.siglen = siglen;
+
+ ret = ecc_verify_internal(&cbdata, data, datasz);
+
+ if (cbdata.keyfp != NULL)
+ fclose(cbdata.keyfp);
+
+ return (ret == 0);
+}
+
+static bool
+ecc_verify_cert(const struct pkgsign_ctx *sctx, int fd,
+ const char *sigfile, const unsigned char *key, int keylen,
+ unsigned char *sig, int siglen)
+{
+ bool ret;
+ char *sha256;
+
+ ret = false;
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ warn("lseek");
+ return (false);
+ }
+
+ if ((sha256 = sha256_fd(fd)) != NULL) {
+ ret = ecc_verify_data(sctx, sha256, strlen(sha256), sigfile, key,
+ keylen, sig, siglen);
+ free(sha256);
+ }
+
+ return (ret);
+}
+
+static int
+ecc_new(const char *name __unused, struct pkgsign_ctx *sctx)
+{
+ struct ecc_sign_ctx *keyinfo = ECC_CTX(sctx);
+ int ret;
+
+ ret = 1;
+ if (STREQ(name, "ecc") || STREQ(name, "eddsa")) {
+ keyinfo->sig_alg = EDDSA25519;
+ keyinfo->sig_hash = SHA512;
+ ret = import_params(&keyinfo->params, &wei25519_str_params);
+ } else if (STREQ(name, "ecdsa")) {
+ keyinfo->sig_alg = ECDSA;
+ keyinfo->sig_hash = SHA256;
+ ret = import_params(&keyinfo->params, &secp256k1_str_params);
+ }
+
+ if (ret != 0)
+ return (1);
+
+ return (0);
+}
+
+const struct pkgsign_ops pkgsign_ecc = {
+ .pkgsign_ctx_size = sizeof(struct ecc_sign_ctx),
+ .pkgsign_new = ecc_new,
+ .pkgsign_verify_cert = ecc_verify_cert,
+ .pkgsign_verify_data = ecc_verify_data,
+};
diff --git a/usr.sbin/pkg/pkg.h b/usr.sbin/pkg/pkg.h
--- a/usr.sbin/pkg/pkg.h
+++ b/usr.sbin/pkg/pkg.h
@@ -51,10 +51,12 @@
pkgsign_verify_data_cb *pkgsign_verify_data;
};
+extern const struct pkgsign_ops pkgsign_ecc;
extern const struct pkgsign_ops pkgsign_rsa;
struct sig_cert {
char *name;
+ char *type;
unsigned char *sig;
int siglen;
unsigned char *cert;
@@ -63,6 +65,7 @@
};
struct pubkey {
+ char *sigtype;
unsigned char *sig;
int siglen;
};
diff --git a/usr.sbin/pkg/pkg.c b/usr.sbin/pkg/pkg.c
--- a/usr.sbin/pkg/pkg.c
+++ b/usr.sbin/pkg/pkg.c
@@ -55,6 +55,8 @@
#include "config.h"
#include "hash.h"
+#define PKGSIGN_MARKER "$PKGSIGN:"
+
static const struct pkgsign_impl {
const char *pi_name;
const struct pkgsign_ops *pi_ops;
@@ -63,6 +65,18 @@
.pi_name = "rsa",
.pi_ops = &pkgsign_rsa,
},
+ {
+ .pi_name = "ecc",
+ .pi_ops = &pkgsign_ecc,
+ },
+ {
+ .pi_name = "ecdsa",
+ .pi_ops = &pkgsign_ecc,
+ },
+ {
+ .pi_name = "eddsa",
+ .pi_ops = &pkgsign_ecc,
+ },
};
typedef enum {
@@ -488,11 +502,41 @@
return (obuf);
}
+/*
+ * Returns a copy of the signature type stored on the heap, and advances *bufp
+ * past the type.
+ */
+static char *
+parse_sigtype(char **bufp, size_t *bufszp)
+{
+ char *buf = *bufp;
+ char *endp;
+ char *sigtype;
+ size_t bufsz = *bufszp;
+
+ if (bufsz <= sizeof(PKGSIGN_MARKER) - 1 ||
+ strncmp(buf, PKGSIGN_MARKER, sizeof(PKGSIGN_MARKER) - 1) != 0)
+ goto dflt;
+
+ buf += sizeof(PKGSIGN_MARKER) - 1;
+ endp = strchr(buf, '$');
+ if (endp == NULL)
+ goto dflt;
+
+ sigtype = strndup(buf, endp - buf);
+ *bufp = endp + 1;
+ *bufszp -= *bufp - buf;
+
+ return (sigtype);
+dflt:
+ return (strdup("rsa"));
+}
+
static struct pubkey *
read_pubkey(int fd)
{
struct pubkey *pk;
- char *sigb;
+ char *osigb, *sigb, *sigtype;
size_t sigsz;
if (lseek(fd, 0, 0) == -1) {
@@ -500,13 +544,15 @@
return (NULL);
}
- sigb = pkg_read_fd(fd, &sigsz);
+ osigb = sigb = pkg_read_fd(fd, &sigsz);
+ sigtype = parse_sigtype(&sigb, &sigsz);
pk = calloc(1, sizeof(struct pubkey));
pk->siglen = sigsz;
pk->sig = calloc(1, pk->siglen);
memcpy(pk->sig, sigb, pk->siglen);
- free(sigb);
+ pk->sigtype = sigtype;
+ free(osigb);
return (pk);
}
@@ -515,17 +561,18 @@
parse_cert(int fd) {
int my_fd;
struct sig_cert *sc;
- FILE *fp, *sigfp, *certfp, *tmpfp;
+ FILE *fp, *sigfp, *certfp, *tmpfp, *typefp;
char *line;
- char *sig, *cert;
- size_t linecap, sigsz, certsz;
+ char *sig, *cert, *type;
+ size_t linecap, sigsz, certsz, typesz;
ssize_t linelen;
+ bool end_seen;
sc = NULL;
line = NULL;
linecap = 0;
- sig = cert = NULL;
- sigfp = certfp = tmpfp = NULL;
+ sig = cert = type = NULL;
+ sigfp = certfp = tmpfp = typefp = NULL;
if (lseek(fd, 0, 0) == -1) {
warn("lseek");
@@ -544,22 +591,30 @@
return (NULL);
}
- sigsz = certsz = 0;
+ sigsz = certsz = typesz = 0;
sigfp = open_memstream(&sig, &sigsz);
if (sigfp == NULL)
err(EXIT_FAILURE, "open_memstream()");
certfp = open_memstream(&cert, &certsz);
if (certfp == NULL)
err(EXIT_FAILURE, "open_memstream()");
+ typefp = open_memstream(&type, &typesz);
+ if (typefp == NULL)
+ err(EXIT_FAILURE, "open_memstream()");
+ end_seen = false;
while ((linelen = getline(&line, &linecap, fp)) > 0) {
if (strcmp(line, "SIGNATURE\n") == 0) {
tmpfp = sigfp;
continue;
+ } else if (strcmp(line, "TYPE\n") == 0) {
+ tmpfp = typefp;
+ continue;
} else if (strcmp(line, "CERT\n") == 0) {
tmpfp = certfp;
continue;
} else if (strcmp(line, "END\n") == 0) {
+ end_seen = true;
break;
}
if (tmpfp != NULL)
@@ -569,11 +624,28 @@
fclose(fp);
fclose(sigfp);
fclose(certfp);
+ fclose(typefp);
sc = calloc(1, sizeof(struct sig_cert));
sc->siglen = sigsz -1; /* Trim out unrelated trailing newline */
sc->sig = sig;
+ if (typesz == 0) {
+ sc->type = strdup("rsa");
+ free(type);
+ } else {
+ assert(type[typesz - 1] == '\n');
+ type[typesz - 1] = '\0';
+ sc->type = type;
+ }
+
+ /*
+ * cert could be DER-encoded rather than PEM, so strip off any trailing
+ * END marker if we ran over it.
+ */
+ if (!end_seen && certsz > 4 &&
+ strcmp(&cert[certsz - 4], "END\n") == 0)
+ certsz -= 4;
sc->certlen = certsz;
sc->cert = cert;
@@ -610,16 +682,23 @@
goto cleanup;
}
- /* Future types shouldn't do this. */
- if ((data = sha256_fd(fd_pkg)) == NULL) {
- warnx("Error creating SHA256 hash for package");
- goto cleanup;
- }
+ if (strcmp(pk->sigtype, "rsa") == 0) {
+ /* Future types shouldn't do this. */
+ if ((data = sha256_fd(fd_pkg)) == NULL) {
+ warnx("Error creating SHA256 hash for package");
+ goto cleanup;
+ }
- datasz = strlen(data);
+ datasz = strlen(data);
+ } else {
+ if ((data = pkg_read_fd(fd_pkg, &datasz)) == NULL) {
+ warnx("Failed to read package data");
+ goto cleanup;
+ }
+ }
- if (pkgsign_new("rsa", &sctx) != 0) {
- warnx("Failed to fetch 'rsa' signer");
+ if (pkgsign_new(pk->sigtype, &sctx) != 0) {
+ warnx("Failed to fetch '%s' signer", pk->sigtype);
goto cleanup;
}
@@ -722,7 +801,7 @@
goto cleanup;
}
- if (pkgsign_new("rsa", &sctx) != 0) {
+ if (pkgsign_new(sc->type, &sctx) != 0) {
fprintf(stderr, "Failed to fetch 'rsa' signer\n");
goto cleanup;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Apr 20, 9:00 PM (22 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31864364
Default Alt Text
D48108.id148010.diff (21 KB)
Attached To
Mode
D48108: pkg: finish adding the ECC signer and signature type bits
Attached
Detach File
Event Timeline
Log In to Comment