summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2015-09-16 21:00:21 +0000
committerdelphij <delphij@FreeBSD.org>2015-09-16 21:00:21 +0000
commit4c99fecba230a99e9d8eb1b0bceff0241aa0a017 (patch)
tree377bcf6f26b4725982781ec71ec84ac324160469
parentec93d5dbe4b95ced72fd0f81a1c31f62248298a9 (diff)
downloadFreeBSD-src-4c99fecba230a99e9d8eb1b0bceff0241aa0a017.zip
FreeBSD-src-4c99fecba230a99e9d8eb1b0bceff0241aa0a017.tar.gz
Implement pubkey support for pkg(7) bootstrap. [EN-15:18]
Approved by: so
-rw-r--r--UPDATING4
-rw-r--r--sys/conf/newvers.sh2
-rw-r--r--usr.sbin/pkg/config.c11
-rw-r--r--usr.sbin/pkg/config.h1
-rw-r--r--usr.sbin/pkg/pkg.c197
5 files changed, 183 insertions, 32 deletions
diff --git a/UPDATING b/UPDATING
index e0256a0..b8b197f 100644
--- a/UPDATING
+++ b/UPDATING
@@ -16,6 +16,10 @@ from older versions of FreeBSD, try WITHOUT_CLANG to bootstrap to the tip of
stable/10, and then rebuild without this option. The bootstrap process from
older version of current is a bit fragile.
+20150916: p20 FreeBSD-EN-15:18.pkg
+
+ Implement pubkey support for pkg(7) bootstrap. [EN-15:18]
+
20150825: p19 FreeBSD-SA-15:21.amd64
FreeBSD-SA-15:22.openssh
FreeBSD-EN-15:14.ixgbe
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index a20337d..d6f8167 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -32,7 +32,7 @@
TYPE="FreeBSD"
REVISION="10.1"
-BRANCH="RELEASE-p19"
+BRANCH="RELEASE-p20"
if [ "X${BRANCH_OVERRIDE}" != "X" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
diff --git a/usr.sbin/pkg/config.c b/usr.sbin/pkg/config.c
index fded95e..54a0491 100644
--- a/usr.sbin/pkg/config.c
+++ b/usr.sbin/pkg/config.c
@@ -133,6 +133,15 @@ static struct config_entry c[] = {
false,
true,
},
+ [PUBKEY] = {
+ PKG_CONFIG_STRING,
+ "PUBKEY",
+ NULL,
+ NULL,
+ NULL,
+ false,
+ false
+ }
};
static const char *
@@ -550,6 +559,8 @@ config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
sbuf_cpy(buf, "SIGNATURE_TYPE");
else if (strcasecmp(key, "fingerprints") == 0)
sbuf_cpy(buf, "FINGERPRINTS");
+ else if (strcasecmp(key, "pubkey") == 0)
+ sbuf_cpy(buf, "PUBKEY");
else if (strcasecmp(key, "enabled") == 0) {
if ((cur->type != UCL_BOOLEAN) ||
!ucl_object_toboolean(cur))
diff --git a/usr.sbin/pkg/config.h b/usr.sbin/pkg/config.h
index ea0d000..4ff0a16 100644
--- a/usr.sbin/pkg/config.h
+++ b/usr.sbin/pkg/config.h
@@ -40,6 +40,7 @@ typedef enum {
SIGNATURE_TYPE,
FINGERPRINTS,
REPOS_DIR,
+ PUBKEY,
CONFIG_SIZE
} pkg_config_key;
diff --git a/usr.sbin/pkg/pkg.c b/usr.sbin/pkg/pkg.c
index 49f60f0..a8fc22c 100644
--- a/usr.sbin/pkg/pkg.c
+++ b/usr.sbin/pkg/pkg.c
@@ -66,6 +66,11 @@ struct sig_cert {
bool trusted;
};
+struct pubkey {
+ unsigned char *sig;
+ int siglen;
+};
+
typedef enum {
HASH_UNKNOWN,
HASH_SHA256,
@@ -474,6 +479,25 @@ cleanup:
}
static EVP_PKEY *
+load_public_key_file(const char *file)
+{
+ EVP_PKEY *pkey;
+ BIO *bp;
+ char errbuf[1024];
+
+ bp = BIO_new_file(file, "r");
+ if (!bp)
+ errx(EXIT_FAILURE, "Unable to read %s", file);
+
+ if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL)
+ warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf));
+
+ BIO_free(bp);
+
+ return (pkey);
+}
+
+static EVP_PKEY *
load_public_key_buf(const unsigned char *cert, int certlen)
{
EVP_PKEY *pkey;
@@ -491,8 +515,8 @@ load_public_key_buf(const unsigned char *cert, int certlen)
}
static bool
-rsa_verify_cert(int fd, const unsigned char *key, int keylen,
- unsigned char *sig, int siglen)
+rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key,
+ int keylen, unsigned char *sig, int siglen)
{
EVP_MD_CTX *mdctx;
EVP_PKEY *pkey;
@@ -504,6 +528,8 @@ rsa_verify_cert(int fd, const unsigned char *key, int keylen,
mdctx = NULL;
ret = false;
+ SSL_load_error_strings();
+
/* Compute SHA256 of the package. */
if (lseek(fd, 0, 0) == -1) {
warn("lseek");
@@ -514,9 +540,16 @@ rsa_verify_cert(int fd, const unsigned char *key, int keylen,
goto cleanup;
}
- if ((pkey = load_public_key_buf(key, keylen)) == NULL) {
- warnx("Error reading public key");
- goto cleanup;
+ if (sigfile != NULL) {
+ if ((pkey = load_public_key_file(sigfile)) == NULL) {
+ warnx("Error reading public key");
+ goto cleanup;
+ }
+ } else {
+ if ((pkey = load_public_key_buf(key, keylen)) == NULL) {
+ warnx("Error reading public key");
+ goto cleanup;
+ }
}
/* Verify signature of the SHA256(pkg) is valid. */
@@ -556,6 +589,35 @@ cleanup:
return (ret);
}
+static struct pubkey *
+read_pubkey(int fd)
+{
+ struct pubkey *pk;
+ struct sbuf *sig;
+ char buf[4096];
+ int r;
+
+ if (lseek(fd, 0, 0) == -1) {
+ warn("lseek");
+ return (NULL);
+ }
+
+ sig = sbuf_new_auto();
+
+ while ((r = read(fd, buf, sizeof(buf))) >0) {
+ sbuf_bcat(sig, buf, r);
+ }
+
+ sbuf_finish(sig);
+ pk = calloc(1, sizeof(struct pubkey));
+ pk->siglen = sbuf_len(sig);
+ pk->sig = calloc(1, pk->siglen);
+ memcpy(pk->sig, sbuf_data(sig), pk->siglen);
+ sbuf_delete(sig);
+
+ return (pk);
+}
+
static struct sig_cert *
parse_cert(int fd) {
int my_fd;
@@ -629,6 +691,45 @@ parse_cert(int fd) {
}
static bool
+verify_pubsignature(int fd_pkg, int fd_sig)
+{
+ struct pubkey *pk;
+ const char *pubkey;
+ bool ret;
+
+ pk = NULL;
+ pubkey = NULL;
+ ret = false;
+ if (config_string(PUBKEY, &pubkey) != 0) {
+ warnx("No CONFIG_PUBKEY defined");
+ goto cleanup;
+ }
+
+ if ((pk = read_pubkey(fd_sig)) == NULL) {
+ warnx("Error reading signature");
+ goto cleanup;
+ }
+
+ /* Verify the signature. */
+ printf("Verifying signature with public key %s... ", pubkey);
+ if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig,
+ pk->siglen) == false) {
+ fprintf(stderr, "Signature is not valid\n");
+ goto cleanup;
+ }
+
+ ret = true;
+
+cleanup:
+ if (pk) {
+ free(pk->sig);
+ free(pk);
+ }
+
+ return (ret);
+}
+
+static bool
verify_signature(int fd_pkg, int fd_sig)
{
struct fingerprint_list *trusted, *revoked;
@@ -706,7 +807,7 @@ verify_signature(int fd_pkg, int fd_sig)
/* Verify the signature. */
printf("Verifying signature with trusted certificate %s... ", sc->name);
- if (rsa_verify_cert(fd_pkg, sc->cert, sc->certlen, sc->sig,
+ if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig,
sc->siglen) == false) {
fprintf(stderr, "Signature is not valid\n");
goto cleanup;
@@ -775,24 +876,42 @@ bootstrap_pkg(bool force)
if (signature_type != NULL &&
strcasecmp(signature_type, "NONE") != 0) {
- if (strcasecmp(signature_type, "FINGERPRINTS") != 0) {
- warnx("Signature type %s is not supported for "
- "bootstrapping.", signature_type);
- goto cleanup;
- }
+ if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
- snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX",
- getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
- snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig",
- packagesite);
+ snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX",
+ getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
+ snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig",
+ packagesite);
- if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
- fprintf(stderr, "Signature for pkg not available.\n");
- goto fetchfail;
- }
+ if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
+ fprintf(stderr, "Signature for pkg not "
+ "available.\n");
+ goto fetchfail;
+ }
+
+ if (verify_signature(fd_pkg, fd_sig) == false)
+ goto cleanup;
+ } else if (strcasecmp(signature_type, "PUBKEY") == 0) {
- if (verify_signature(fd_pkg, fd_sig) == false)
+ snprintf(tmpsig, MAXPATHLEN,
+ "%s/pkg.txz.pubkeysig.XXXXXX",
+ getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
+ snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig",
+ packagesite);
+
+ if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
+ fprintf(stderr, "Signature for pkg not "
+ "available.\n");
+ goto fetchfail;
+ }
+
+ if (verify_pubsignature(fd_pkg, fd_sig) == false)
+ goto cleanup;
+ } else {
+ warnx("Signature type %s is not supported for "
+ "bootstrapping.", signature_type);
goto cleanup;
+ }
}
if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
@@ -861,21 +980,37 @@ bootstrap_pkg_local(const char *pkgpath, bool force)
}
if (signature_type != NULL &&
strcasecmp(signature_type, "NONE") != 0) {
- if (strcasecmp(signature_type, "FINGERPRINTS") != 0) {
- warnx("Signature type %s is not supported for "
- "bootstrapping.", signature_type);
- goto cleanup;
- }
+ if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
- snprintf(path, sizeof(path), "%s.sig", pkgpath);
+ snprintf(path, sizeof(path), "%s.sig", pkgpath);
- if ((fd_sig = open(path, O_RDONLY)) == -1) {
- fprintf(stderr, "Signature for pkg not available.\n");
- goto cleanup;
- }
+ if ((fd_sig = open(path, O_RDONLY)) == -1) {
+ fprintf(stderr, "Signature for pkg not "
+ "available.\n");
+ goto cleanup;
+ }
- if (verify_signature(fd_pkg, fd_sig) == false)
+ if (verify_signature(fd_pkg, fd_sig) == false)
+ goto cleanup;
+
+ } else if (strcasecmp(signature_type, "PUBKEY") == 0) {
+
+ snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath);
+
+ if ((fd_sig = open(path, O_RDONLY)) == -1) {
+ fprintf(stderr, "Signature for pkg not "
+ "available.\n");
+ goto cleanup;
+ }
+
+ if (verify_pubsignature(fd_pkg, fd_sig) == false)
+ goto cleanup;
+
+ } else {
+ warnx("Signature type %s is not supported for "
+ "bootstrapping.", signature_type);
goto cleanup;
+ }
}
if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
OpenPOWER on IntegriCloud