357 lines
8.6 KiB
Diff
357 lines
8.6 KiB
Diff
Index: usr.sbin/pkg/config.c
|
|
===================================================================
|
|
--- usr.sbin/pkg/config.c (revision 287854)
|
|
+++ usr.sbin/pkg/config.c (working copy)
|
|
@@ -131,6 +131,15 @@ static struct config_entry c[] = {
|
|
false,
|
|
true,
|
|
},
|
|
+ [PUBKEY] = {
|
|
+ PKG_CONFIG_STRING,
|
|
+ "PUBKEY",
|
|
+ NULL,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ false,
|
|
+ false
|
|
+ }
|
|
};
|
|
|
|
static const char *
|
|
@@ -347,6 +356,8 @@ config_parse(ucl_object_t *obj, pkg_conf_file_t co
|
|
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))
|
|
Index: usr.sbin/pkg/config.h
|
|
===================================================================
|
|
--- usr.sbin/pkg/config.h (revision 287854)
|
|
+++ usr.sbin/pkg/config.h (working copy)
|
|
@@ -40,6 +40,7 @@ typedef enum {
|
|
SIGNATURE_TYPE,
|
|
FINGERPRINTS,
|
|
REPOS_DIR,
|
|
+ PUBKEY,
|
|
CONFIG_SIZE
|
|
} pkg_config_key;
|
|
|
|
Index: usr.sbin/pkg/pkg.c
|
|
===================================================================
|
|
--- usr.sbin/pkg/pkg.c (revision 287854)
|
|
+++ usr.sbin/pkg/pkg.c (working copy)
|
|
@@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$");
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
-#include <time.h>
|
|
#include <unistd.h>
|
|
#include <ucl.h>
|
|
|
|
@@ -66,6 +65,11 @@ struct sig_cert {
|
|
bool trusted;
|
|
};
|
|
|
|
+struct pubkey {
|
|
+ unsigned char *sig;
|
|
+ int siglen;
|
|
+};
|
|
+
|
|
typedef enum {
|
|
HASH_UNKNOWN,
|
|
HASH_SHA256,
|
|
@@ -176,14 +180,11 @@ fetch_to_fd(const char *url, char *path)
|
|
/* To store _https._tcp. + hostname + \0 */
|
|
int fd;
|
|
int retry, max_retry;
|
|
- off_t done, r;
|
|
- time_t now, last;
|
|
+ ssize_t r;
|
|
char buf[10240];
|
|
char zone[MAXHOSTNAMELEN + 13];
|
|
static const char *mirror_type = NULL;
|
|
|
|
- done = 0;
|
|
- last = 0;
|
|
max_retry = 3;
|
|
current = mirrors = NULL;
|
|
remote = NULL;
|
|
@@ -233,19 +234,16 @@ fetch_to_fd(const char *url, char *path)
|
|
}
|
|
}
|
|
|
|
- while (done < st.size) {
|
|
- if ((r = fread(buf, 1, sizeof(buf), remote)) < 1)
|
|
- break;
|
|
-
|
|
+ while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) {
|
|
if (write(fd, buf, r) != r) {
|
|
warn("write()");
|
|
goto fetchfail;
|
|
}
|
|
+ }
|
|
|
|
- done += r;
|
|
- now = time(NULL);
|
|
- if (now > last || done == st.size)
|
|
- last = now;
|
|
+ if (r != 0) {
|
|
+ warn("An error occurred while fetching pkg(8)");
|
|
+ goto fetchfail;
|
|
}
|
|
|
|
if (ferror(remote))
|
|
@@ -480,6 +478,29 @@ cleanup:
|
|
}
|
|
|
|
static RSA *
|
|
+load_rsa_public_key_file(const char *file)
|
|
+{
|
|
+ RSA *rsa = NULL;
|
|
+ BIO *bp;
|
|
+ char errbuf[1024];
|
|
+
|
|
+ bp = BIO_new_file(file, "r");
|
|
+ if (!bp)
|
|
+ errx(EXIT_FAILURE, "Unable to read %s", file);
|
|
+
|
|
+ if (!PEM_read_bio_RSA_PUBKEY(bp, &rsa, NULL, NULL)) {
|
|
+ warn("error reading public key: %s",
|
|
+ ERR_error_string(ERR_get_error(), errbuf));
|
|
+ BIO_free(bp);
|
|
+ return (NULL);
|
|
+ }
|
|
+
|
|
+ BIO_free(bp);
|
|
+
|
|
+ return (rsa);
|
|
+}
|
|
+
|
|
+static RSA *
|
|
load_rsa_public_key_buf(unsigned char *cert, int certlen)
|
|
{
|
|
RSA *rsa = NULL;
|
|
@@ -499,8 +520,8 @@ load_rsa_public_key_buf(unsigned char *cert, int c
|
|
|
|
|
|
static bool
|
|
-rsa_verify_cert(int fd, unsigned char *key, int keylen,
|
|
- unsigned char *sig, int siglen)
|
|
+rsa_verify_cert(int fd, const char *sigfile, unsigned char *key,
|
|
+ int keylen, unsigned char *sig, int siglen)
|
|
{
|
|
char sha256[SHA256_DIGEST_LENGTH *2 +1];
|
|
char hash[SHA256_DIGEST_LENGTH];
|
|
@@ -517,7 +538,11 @@ static bool
|
|
|
|
sha256_buf_bin(sha256, strlen(sha256), hash);
|
|
|
|
- rsa = load_rsa_public_key_buf(key, keylen);
|
|
+ if (sigfile != NULL) {
|
|
+ rsa = load_rsa_public_key_file(sigfile);
|
|
+ } else {
|
|
+ rsa = load_rsa_public_key_buf(key, keylen);
|
|
+ }
|
|
if (rsa == NULL)
|
|
return (false);
|
|
ret = RSA_verify(NID_sha256, hash, sizeof(hash), sig, siglen, rsa);
|
|
@@ -532,6 +557,35 @@ static bool
|
|
return (true);
|
|
}
|
|
|
|
+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;
|
|
@@ -605,6 +659,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;
|
|
@@ -682,7 +775,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) {
|
|
printf("failed\n");
|
|
fprintf(stderr, "Signature is not valid\n");
|
|
@@ -750,24 +843,42 @@ bootstrap_pkg(bool force)
|
|
|
|
if (signature_type != NULL &&
|
|
strcasecmp(signature_type, "NONE") != 0) {
|
|
- if (strcasecmp(signature_type, "FINGERPRINTS") != 0) {
|
|
+ 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);
|
|
+
|
|
+ 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) {
|
|
+
|
|
+ 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;
|
|
}
|
|
-
|
|
- 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 (verify_signature(fd_pkg, fd_sig) == false)
|
|
- goto cleanup;
|
|
}
|
|
|
|
if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
|
|
@@ -841,21 +952,37 @@ bootstrap_pkg_local(const char *pkgpath, bool forc
|
|
}
|
|
if (signature_type != NULL &&
|
|
strcasecmp(signature_type, "NONE") != 0) {
|
|
- if (strcasecmp(signature_type, "FINGERPRINTS") != 0) {
|
|
+ if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
|
|
+
|
|
+ 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 (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;
|
|
}
|
|
-
|
|
- 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 (verify_signature(fd_pkg, fd_sig) == false)
|
|
- goto cleanup;
|
|
}
|
|
|
|
if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
|