320 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			320 lines
		
	
	
	
		
			7.8 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 int
 | |
| @@ -231,6 +240,8 @@ config_parse(const ucl_object_t *obj, pkg_conf_fil
 | |
|  				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)
 | |
| @@ -65,6 +65,11 @@ struct sig_cert {
 | |
|  	bool trusted;
 | |
|  };
 | |
|  
 | |
| +struct pubkey {
 | |
| +	unsigned char *sig;
 | |
| +	int siglen;
 | |
| +};
 | |
| +
 | |
|  typedef enum {
 | |
|         HASH_UNKNOWN,
 | |
|         HASH_SHA256,
 | |
| @@ -470,6 +475,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;
 | |
| @@ -487,8 +511,8 @@ load_public_key_buf(const unsigned char *cert, int
 | |
|  }
 | |
|  
 | |
|  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;
 | |
| @@ -500,6 +524,8 @@ static bool
 | |
|  	mdctx = NULL;
 | |
|  	ret = false;
 | |
|  
 | |
| +	SSL_load_error_strings();
 | |
| +
 | |
|  	/* Compute SHA256 of the package. */
 | |
|  	if (lseek(fd, 0, 0) == -1) {
 | |
|  		warn("lseek");
 | |
| @@ -510,9 +536,16 @@ static bool
 | |
|  		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. */
 | |
| @@ -552,6 +585,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;
 | |
| @@ -625,6 +687,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;
 | |
| @@ -702,7 +803,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;
 | |
| @@ -768,24 +869,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)
 | |
| @@ -862,21 +981,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)
 |