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)
 |