pkg: abstract rsa out behind a pkgsign API

This mirrors a change we made in pkg(8), and will be used to next add
another signer that does ECC.

Reviewed by:	bapt, emaste

(cherry picked from commit 5862580ded)
This commit is contained in:
Kyle Evans 2025-01-01 15:10:27 -06:00
parent 836f1da80e
commit 1e3003bed3
3 changed files with 110 additions and 9 deletions

View file

@ -35,6 +35,7 @@
#include <archive.h>
#include <archive_entry.h>
#include <assert.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
@ -55,6 +56,16 @@
#include "config.h"
#include "hash.h"
static const struct pkgsign_impl {
const char *pi_name;
const struct pkgsign_ops *pi_ops;
} pkgsign_builtins[] = {
{
.pi_name = "rsa",
.pi_ops = &pkgsign_rsa,
},
};
typedef enum {
HASH_UNKNOWN,
HASH_SHA256,
@ -77,6 +88,61 @@ STAILQ_HEAD(fingerprint_list, fingerprint);
static int debug;
static int
pkgsign_new(const char *name, struct pkgsign_ctx **ctx)
{
const 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 (ENOENT);
ctx_size = ops->pkgsign_ctx_size;
if (ctx_size == 0)
ctx_size = sizeof(*nctx);
assert(ctx_size >= sizeof(*nctx));
nctx = calloc(1, ctx_size);
if (nctx == NULL)
err(EXIT_FAILURE, "calloc");
nctx->impl = impl;
ret = 0;
if (ops->pkgsign_new != NULL)
ret = (*ops->pkgsign_new)(name, nctx);
if (ret != 0) {
free(nctx);
return (ret);
}
*ctx = nctx;
return (0);
}
static bool
pkgsign_verify_cert(const struct pkgsign_ctx *ctx, int fd, const char *sigfile,
const unsigned char *key, int keylen, unsigned char *sig, int siglen)
{
return ((*ctx->impl->pi_ops->pkgsign_verify_cert)(ctx, fd, sigfile,
key, keylen, sig, siglen));
}
static int
extract_pkg_static(int fd, char *p, int sz)
{
@ -509,10 +575,12 @@ verify_pubsignature(int fd_pkg, int fd_sig)
{
struct pubkey *pk;
const char *pubkey;
struct pkgsign_ctx *sctx;
bool ret;
pk = NULL;
pubkey = NULL;
sctx = NULL;
ret = false;
if (config_string(PUBKEY, &pubkey) != 0) {
warnx("No CONFIG_PUBKEY defined");
@ -524,9 +592,14 @@ verify_pubsignature(int fd_pkg, int fd_sig)
goto cleanup;
}
if (pkgsign_new("rsa", &sctx) != 0) {
warnx("Failed to fetch 'rsa' signer");
goto cleanup;
}
/* Verify the signature. */
printf("Verifying signature with public key %s... ", pubkey);
if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig,
if (pkgsign_verify_cert(sctx, fd_pkg, pubkey, NULL, 0, pk->sig,
pk->siglen) == false) {
fprintf(stderr, "Signature is not valid\n");
goto cleanup;
@ -549,6 +622,7 @@ verify_signature(int fd_pkg, int fd_sig)
struct fingerprint_list *trusted, *revoked;
struct fingerprint *fingerprint;
struct sig_cert *sc;
struct pkgsign_ctx *sctx;
bool ret;
int trusted_count, revoked_count;
const char *fingerprints;
@ -557,6 +631,7 @@ verify_signature(int fd_pkg, int fd_sig)
hash = NULL;
sc = NULL;
sctx = NULL;
trusted = revoked = NULL;
ret = false;
@ -620,10 +695,15 @@ verify_signature(int fd_pkg, int fd_sig)
goto cleanup;
}
if (pkgsign_new("rsa", &sctx) != 0) {
fprintf(stderr, "Failed to fetch 'rsa' signer\n");
goto cleanup;
}
/* Verify the signature. */
printf("Verifying signature with trusted certificate %s... ", sc->name);
if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig,
sc->siglen) == false) {
if (pkgsign_verify_cert(sctx, fd_pkg, NULL, sc->cert, sc->certlen,
sc->sig, sc->siglen) == false) {
fprintf(stderr, "Signature is not valid\n");
goto cleanup;
}

View file

@ -30,6 +30,25 @@
#ifndef _PKG_H
#define _PKG_H
#include <stdbool.h>
struct pkgsign_ctx {
const struct pkgsign_impl *impl;
};
/* Tentatively won't be needing to free any state, all allocated in the ctx. */
typedef int pkgsign_new_cb(const char *, struct pkgsign_ctx *);
typedef bool pkgsign_verify_cert_cb(const struct pkgsign_ctx *, int,
const char *, const unsigned char *, int, unsigned char *, int);
struct pkgsign_ops {
size_t pkgsign_ctx_size;
pkgsign_new_cb *pkgsign_new;
pkgsign_verify_cert_cb *pkgsign_verify_cert;
};
extern const struct pkgsign_ops pkgsign_rsa;
struct sig_cert {
char *name;
unsigned char *sig;
@ -44,9 +63,6 @@ struct pubkey {
int siglen;
};
bool rsa_verify_cert(int, const char *, const unsigned char *, int,
unsigned char *, int);
char *pkg_read_fd(int fd, size_t *osz);
#endif /* _PKG_H */

View file

@ -77,9 +77,10 @@ load_public_key_buf(const unsigned char *cert, int certlen)
return (pkey);
}
bool
rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key,
int keylen, unsigned char *sig, int siglen)
static bool
rsa_verify_cert(const struct pkgsign_ctx *ctx __unused, int fd,
const char *sigfile, const unsigned char *key, int keylen,
unsigned char *sig, int siglen)
{
EVP_MD_CTX *mdctx;
EVP_PKEY *pkey;
@ -153,3 +154,7 @@ cleanup:
return (ret);
}
const struct pkgsign_ops pkgsign_rsa = {
.pkgsign_verify_cert = rsa_verify_cert,
};