git: 082f3564f94d - stable/13 - pkg: abstract rsa out behind a pkgsign API

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Sat, 11 Jan 2025 02:49:03 UTC
The branch stable/13 has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=082f3564f94d85054aba8ef4d34fc375611e5387

commit 082f3564f94d85054aba8ef4d34fc375611e5387
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-01-01 21:10:27 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2025-01-11 02:48:30 +0000

    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 5862580ded35e23581291a2e1052f04428369ead)
---
 usr.sbin/pkg/pkg.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 usr.sbin/pkg/pkg.h | 22 ++++++++++++--
 usr.sbin/pkg/rsa.c | 11 +++++--
 3 files changed, 110 insertions(+), 9 deletions(-)

diff --git a/usr.sbin/pkg/pkg.c b/usr.sbin/pkg/pkg.c
index 56bced7b9c5f..5cc9c3b8dbfe 100644
--- a/usr.sbin/pkg/pkg.c
+++ b/usr.sbin/pkg/pkg.c
@@ -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,
@@ -75,6 +86,61 @@ static const char *bootstrap_names []  = {
 
 STAILQ_HEAD(fingerprint_list, fingerprint);
 
+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)
 {
@@ -507,10 +573,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");
@@ -522,9 +590,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;
@@ -547,6 +620,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;
@@ -555,6 +629,7 @@ verify_signature(int fd_pkg, int fd_sig)
 
 	hash = NULL;
 	sc = NULL;
+	sctx = NULL;
 	trusted = revoked = NULL;
 	ret = false;
 
@@ -618,10 +693,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;
 	}
diff --git a/usr.sbin/pkg/pkg.h b/usr.sbin/pkg/pkg.h
index faa2be6c8376..2d0dab96a20f 100644
--- a/usr.sbin/pkg/pkg.h
+++ b/usr.sbin/pkg/pkg.h
@@ -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 */
diff --git a/usr.sbin/pkg/rsa.c b/usr.sbin/pkg/rsa.c
index afc446a6ad06..b6345cdcecb8 100644
--- a/usr.sbin/pkg/rsa.c
+++ b/usr.sbin/pkg/rsa.c
@@ -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,
+};