[arch-projects] [dbscripts][PATCH] Prevent master keys signing packages
Signed-off-by: Allan McRae <allan@archlinux.org> --- config | 1 + db-functions | 14 ++++++++++++++ db-update | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/config b/config index 3df6c95..d1413cc 100644 --- a/config +++ b/config @@ -18,6 +18,7 @@ SOURCE_CLEANUP_DRYRUN=false SOURCE_CLEANUP_KEEP=14 REQUIRE_SIGNATURE=true +MASTER_KEYS=('6AC6A4C2' '824B18E8' '4C7EA887' 'FFF979E7' 'CDFD6BB0') LOCK_DELAY=10 LOCK_TIMEOUT=300 diff --git a/db-functions b/db-functions index bb49894..26e6825 100644 --- a/db-functions +++ b/db-functions @@ -381,6 +381,20 @@ check_pkgsvn() { return 0 } +check_signature() { + local pkgfile="${1}" + + if ! pacman-key -v "${pkgfile}.sig" >/dev/null 2>&1 + return 1 + fi + + for k in ${MASTER_KEYS}; do + if pacman-key -v "${pkgfile}.sig" 2>&1 | grep -q "key ID ${k}" + return 1 + fi + done +} + check_splitpkgs() { local repo="${1}" shift diff --git a/db-update b/db-update index 576fe2b..087a248 100755 --- a/db-update +++ b/db-update @@ -42,7 +42,7 @@ for repo in ${repos[@]}; do if ! check_pkgfile "${pkg}"; then die "Package ${repo}/${pkg##*/} is not consistent with its meta data" fi - if ${REQUIRE_SIGNATURE} && ! pacman-key -v "${pkg}.sig" >/dev/null 2>&1; then + if ${REQUIRE_SIGNATURE} && ! check_pkgsig ${pkg}; then die "Package ${repo}/${pkg##*/} does not have a valid signature" fi if ! check_pkgsvn "${pkg}" "${repo}"; then -- 1.8.4.2
Add function to sign repo database. Enabling signing requires setting SIGN_DB to true and adding the key ID to DB_KEY. The DB_KEY is restricted from signing package files. Signed-off-by: Allan McRae <allan@archlinux.org> --- config | 3 +++ db-functions | 17 ++++++++++++++++- db-move | 6 ++++++ db-remove | 1 + db-repo-add | 1 + db-repo-remove | 1 + db-update | 1 + testing2x | 2 ++ 8 files changed, 31 insertions(+), 1 deletion(-) diff --git a/config b/config index d1413cc..2069565 100644 --- a/config +++ b/config @@ -20,6 +20,9 @@ SOURCE_CLEANUP_KEEP=14 REQUIRE_SIGNATURE=true MASTER_KEYS=('6AC6A4C2' '824B18E8' '4C7EA887' 'FFF979E7' 'CDFD6BB0') +SIGN_DB=false +DB_KEY='' + LOCK_DELAY=10 LOCK_TIMEOUT=300 diff --git a/db-functions b/db-functions index 26e6825..bbbee25 100644 --- a/db-functions +++ b/db-functions @@ -227,6 +227,21 @@ repo_unlock () { #repo_unlock <repo-name> <arch> fi } +# sign_db <repo-name> <arch> +sign_db() { + local repo=$1 + local arch=$2 + local dbfile="${FTP_BASE}/${repo}/os/${arch}/${repo}${DBEXT}" + local filesfile="${FTP_BASE}/${repo}/os/${arch}/${repo}${FILESEXT}" + + if ! $SIGN_DB; the + return 0 + fi + + gpg --homedir=/etc/pacman.d/gnupg/ --default-key ${DB_KEY} --detach-sign ${dbfile} + gpg --homedir=/etc/pacman.d/gnupg/ --default-key ${DB_KEY} --detach-sign ${filesfile} +} + # usage: _grep_pkginfo pkgfile pattern _grep_pkginfo() { local _ret @@ -388,7 +403,7 @@ check_signature() { return 1 fi - for k in ${MASTER_KEYS}; do + for k in ${MASTER_KEYS} ${DB_KEY}; do if pacman-key -v "${pkgfile}.sig" 2>&1 | grep -q "key ID ${k}" return 1 fi diff --git a/db-move b/db-move index 1fa44d4..e51ce02 100755 --- a/db-move +++ b/db-move @@ -120,6 +120,12 @@ for tarch in ${ARCHES[@]}; do done for pkgarch in ${ARCHES[@]}; do + sign_db ${repo_from} ${pkgarch} + sign_db ${repo_to} ${pkgarch} +done + + +for pkgarch in ${ARCHES[@]}; do repo_unlock ${repo_from} ${pkgarch} repo_unlock ${repo_to} ${pkgarch} done diff --git a/db-remove b/db-remove index 25cb9a7..8de0b7f 100755 --- a/db-remove +++ b/db-remove @@ -48,5 +48,6 @@ done for tarch in ${tarches[@]}; do arch_repo_remove "${repo}" "${tarch}" ${remove_pkgs[@]} + sign_db $repo $tarch repo_unlock $repo $tarch done diff --git a/db-repo-add b/db-repo-add index 5d5b653..aa79b9f 100755 --- a/db-repo-add +++ b/db-repo-add @@ -37,5 +37,6 @@ for tarch in ${tarches[@]}; do fi done arch_repo_add "${repo}" "${tarch}" ${pkgfiles[@]} + sign_db $repo $tarch repo_unlock $repo $tarch done diff --git a/db-repo-remove b/db-repo-remove index 2a693f4..2f6ccb7 100755 --- a/db-repo-remove +++ b/db-repo-remove @@ -33,5 +33,6 @@ for tarch in ${tarches[@]}; do msg "Removing $pkgname from [$repo]..." done arch_repo_remove "${repo}" "${tarch}" ${pkgnames[@]} + sign_db $repo $tarch repo_unlock $repo $tarch done diff --git a/db-update b/db-update index 087a248..c82017c 100755 --- a/db-update +++ b/db-update @@ -91,6 +91,7 @@ done for repo in ${repos[@]}; do for pkgarch in ${ARCHES[@]}; do + sign_db ${repo} ${pkgarch} repo_unlock ${repo} ${pkgarch} done done diff --git a/testing2x b/testing2x index 369857f..8ce5f2b 100755 --- a/testing2x +++ b/testing2x @@ -47,10 +47,12 @@ for pkgbase in $*; do done for pkgarch in ${ARCHES[@]}; do + sign_db ${TESTING_REPO} ${pkgarch} repo_unlock ${TESTING_REPO} ${pkgarch} done for repo in ${STABLE_REPOS[@]}; do for pkgarch in ${ARCHES[@]}; do + sign_db ${repo} ${pkgarch} repo_unlock ${repo} ${pkgarch} done if [ -n "${pkgs[${repo}]}" ]; then -- 1.8.4.2
On 03/11/13 11:19, Allan McRae wrote:
Add function to sign repo database. Enabling signing requires setting SIGN_DB to true and adding the key ID to DB_KEY. The DB_KEY is restricted from signing package files.
Signed-off-by: Allan McRae <allan@archlinux.org> ---
GPG does not have a concept of some keys being valid for some tasks. So pacman can not have this concept without implementing a complete hack or requiring two separate keyrings (one for databases and one for packages). Both of these are not going to happen, so we need to deal with restricting key usage in dbscripts. The idea here is that someone creates a repo signing key and all master keys sign it. Then a subkey is created and put on nymeria. If we have issues, the subkey is revoked and a new subkey is created. Note that the patch assumes the db key will be added to nymeria's pacman keyring which is located in the default location. Allan
Am 03.11.2013 02:32, schrieb Allan McRae:
On 03/11/13 11:19, Allan McRae wrote:
Add function to sign repo database. Enabling signing requires setting SIGN_DB to true and adding the key ID to DB_KEY. The DB_KEY is restricted from signing package files.
Signed-off-by: Allan McRae <allan@archlinux.org> ---
GPG does not have a concept of some keys being valid for some tasks. So pacman can not have this concept without implementing a complete hack or requiring two separate keyrings (one for databases and one for packages). Both of these are not going to happen, so we need to deal with restricting key usage in dbscripts.
The idea here is that someone creates a repo signing key and all master keys sign it. Then a subkey is created and put on nymeria. If we have issues, the subkey is revoked and a new subkey is created.
Note that the patch assumes the db key will be added to nymeria's pacman keyring which is located in the default location.
Allan
I don't see how this could work. If you sign a package using that key pacman will happily accept it as valid. So if nymeria gets compromised the attacker obtains a valid packager key. Imho implementing db sigs this way is less secure than not implementing it at all. Greetings, Pierre -- Pierre Schmitz, https://pierre-schmitz.com
Am 03.11.2013 09:50, schrieb Pierre Schmitz:
I don't see how this could work. If you sign a package using that key pacman will happily accept it as valid. So if nymeria gets compromised the attacker obtains a valid packager key. Imho implementing db sigs this way is less secure than not implementing it at all.
We can use a subkey of a valid packager key. That way, revoking the subkey is very easy and doesn't need 5 people, but just one. If we secure the private key properly on nymeria (see my first mail), then compromising nymeria is not sufficient, you actually need to become root there (which hopefully shouldn't be too easy). Actually, other distributions have keys on their servers for signatures, too, even to sign packages (I remember seeing very unpersonal, repository-based PGP key on openSuSE).
On 03/11/13 18:50, Pierre Schmitz wrote:
Am 03.11.2013 02:32, schrieb Allan McRae:
On 03/11/13 11:19, Allan McRae wrote:
Add function to sign repo database. Enabling signing requires setting SIGN_DB to true and adding the key ID to DB_KEY. The DB_KEY is restricted from signing package files.
Signed-off-by: Allan McRae <allan@archlinux.org> ---
GPG does not have a concept of some keys being valid for some tasks. So pacman can not have this concept without implementing a complete hack or requiring two separate keyrings (one for databases and one for packages). Both of these are not going to happen, so we need to deal with restricting key usage in dbscripts.
The idea here is that someone creates a repo signing key and all master keys sign it. Then a subkey is created and put on nymeria. If we have issues, the subkey is revoked and a new subkey is created.
Note that the patch assumes the db key will be added to nymeria's pacman keyring which is located in the default location.
Allan
I don't see how this could work. If you sign a package using that key pacman will happily accept it as valid. So if nymeria gets compromised the attacker obtains a valid packager key. Imho implementing db sigs this way is less secure than not implementing it at all.
If an attacker obtains any of our packagers keys then they can sign a package. So by your logic we should not be signing packages. Also, this is the way every other distro signs their databases and packages. And they all use gpgv to verify packages which has no idea about a web of trust. This seems like something we should be able to achieve... Finally, I think signing databases is far more important than signing packages. The most practical attack on Arch is to become a mirror and hold back package updates with known vulnerabilities. Then you even know the IP addresses of people who have the vulnerable package. DB signing stops this as the entire database needs held back and people will notice the lack of updates. Allan
Am 03.11.2013 11:03, schrieb Allan McRae:
If an attacker obtains any of our packagers keys then they can sign a package. So by your logic we should not be signing packages.
Also, this is the way every other distro signs their databases and packages. And they all use gpgv to verify packages which has no idea about a web of trust. This seems like something we should be able to achieve...
Finally, I think signing databases is far more important than signing packages. The most practical attack on Arch is to become a mirror and hold back package updates with known vulnerabilities. Then you even know the IP addresses of people who have the vulnerable package. DB signing stops this as the entire database needs held back and people will notice the lack of updates.
I tend to fully agree with Allan here. We need to sign databases and the risk of having the signing key on nymeria is smaller than you make it look.
On Sun, 03 Nov 2013 20:03:41 +1000 Allan McRae <allan@archlinux.org> wrote:
Finally, I think signing databases is far more important than signing packages. The most practical attack on Arch is to become a mirror and hold back package updates with known vulnerabilities. Then you even know the IP addresses of people who have the vulnerable package. DB signing stops this as the entire database needs held back and people will notice the lack of updates.
Imo it would also be useful to be able to test checksums of installed binaries to the packages available in the repos. One could possibly even verify the installed packages against another mirror. But in it's essence an improved -Qkk could be useful to verify system integrity. -- Joakim
Am 03.11.2013 02:32, schrieb Allan McRae:
On 03/11/13 11:19, Allan McRae wrote:
Add function to sign repo database. Enabling signing requires setting SIGN_DB to true and adding the key ID to DB_KEY. The DB_KEY is restricted from signing package files.
Signed-off-by: Allan McRae <allan@archlinux.org> ---
GPG does not have a concept of some keys being valid for some tasks. So pacman can not have this concept without implementing a complete hack or requiring two separate keyrings (one for databases and one for packages). Both of these are not going to happen, so we need to deal with restricting key usage in dbscripts.
The idea here is that someone creates a repo signing key and all master keys sign it. Then a subkey is created and put on nymeria. If we have issues, the subkey is revoked and a new subkey is created.
Note that the patch assumes the db key will be added to nymeria's pacman keyring which is located in the default location.
With this implementation, anyone with access to nymeria can simply steal the private key and use it elsewhere. Users shouldn't have access to the private key, they should only have access to a black-box script that signs the database (and only the database) using sudo. However, a clever asshole might then move a file to the database location, run the script and get a valid signature. So, in order for this to happen, the whole /srv/ftp path for repos and pool must be read-only to packagers. Then, a dedicated script must be called using sudo that verifies the signatures of the submitted packages, adjusts the database and then signs it. I was thinking about this for a while (independently of db signatures), but was always too lazy to do it. It's a nice feature to not have packagers mess around with the ftp path manually.
Am 03.11.2013 10:11, schrieb Thomas Bächler:
Am 03.11.2013 02:32, schrieb Allan McRae:
On 03/11/13 11:19, Allan McRae wrote:
Add function to sign repo database. Enabling signing requires setting SIGN_DB to true and adding the key ID to DB_KEY. The DB_KEY is restricted from signing package files.
Signed-off-by: Allan McRae <allan@archlinux.org> ---
GPG does not have a concept of some keys being valid for some tasks. So pacman can not have this concept without implementing a complete hack or requiring two separate keyrings (one for databases and one for packages). Both of these are not going to happen, so we need to deal with restricting key usage in dbscripts.
The idea here is that someone creates a repo signing key and all master keys sign it. Then a subkey is created and put on nymeria. If we have issues, the subkey is revoked and a new subkey is created.
Note that the patch assumes the db key will be added to nymeria's pacman keyring which is located in the default location.
With this implementation, anyone with access to nymeria can simply steal the private key and use it elsewhere.
Users shouldn't have access to the private key, they should only have access to a black-box script that signs the database (and only the database) using sudo.
However, a clever asshole might then move a file to the database location, run the script and get a valid signature.
So, in order for this to happen, the whole /srv/ftp path for repos and pool must be read-only to packagers. Then, a dedicated script must be called using sudo that verifies the signatures of the submitted packages, adjusts the database and then signs it.
I was thinking about this for a while (independently of db signatures), but was always too lazy to do it. It's a nice feature to not have packagers mess around with the ftp path manually.
I wouldn't really trust such a setup. There might always be ways to get root via kernel exploits are issues with suid binaries. It is safer to assume tht nymeria cannot be trusted. Also keep in mind that it is usually hard to tell if a server was not compromised. E.g. someone could obtrain the key but only use it elsewhere (on mirrors or mitm attacks). If nymeria has a valid packager key we could as well sign all packages using that key. I only see two possible solutions here that are safe: * client side db signing (has lots of problems) * pacman has different keyrings/keys for verifing packages and dbs. -- Pierre Schmitz, https://pierre-schmitz.com
participants (4)
-
Allan McRae
-
Joakim Hernberg
-
Pierre Schmitz
-
Thomas Bächler