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 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 + * Copyright (c) 2011-2012 Julien Laffaye + * All rights reserved. + * Copyright (c) 2021 Kyle Evans + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define WITH_STDLIB +#include +#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) (__containerof(c, const struct ecc_sign_ctx, sctx)) +#define ECC_CTX(c) (__containerof(c, struct ecc_sign_ctx, sctx)) + +#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; }