about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--perl/lib/Nix/Manifest.pm37
-rwxr-xr-xscripts/nix-push.in5
2 files changed, 29 insertions, 13 deletions
diff --git a/perl/lib/Nix/Manifest.pm b/perl/lib/Nix/Manifest.pm
index ec3e48fcfbec..b82c82fb253c 100644
--- a/perl/lib/Nix/Manifest.pm
+++ b/perl/lib/Nix/Manifest.pm
@@ -13,7 +13,7 @@ use Nix::Config;
 use Nix::Store;
 
 our @ISA = qw(Exporter);
-our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch deleteOldManifests parseNARInfo);
+our @EXPORT = qw(readManifest writeManifest updateManifestDB addPatch deleteOldManifests parseNARInfo fingerprintPath);
 
 
 sub addNAR {
@@ -395,12 +395,26 @@ sub deleteOldManifests {
 }
 
 
+# Return a fingerprint of a store path to be used in binary cache
+# signatures. It contains the store path, the SHA-256 hash of the
+# contents of the path, and the references.
+sub fingerprintPath {
+    my ($storePath, $narHash, $references) = @_;
+    die if substr($storePath, 0, length($Nix::Config::storeDir)) ne $Nix::Config::storeDir;
+    die if substr($narHash, 0, 7) ne "sha256:";
+    die if length($narHash) != 59;
+    foreach my $ref (@{$references}) {
+        die if substr($ref, 0, length($Nix::Config::storeDir)) ne $Nix::Config::storeDir;
+    }
+    return "1;" . $storePath . ";" . $narHash . ";" . join(",", @{$references});
+}
+
+
 # Parse a NAR info file.
 sub parseNARInfo {
     my ($storePath, $content, $requireValidSig, $location) = @_;
 
     my ($storePath2, $url, $fileHash, $fileSize, $narHash, $narSize, $deriver, $system, $sig);
-    my $signedData = "";
     my $compression = "bzip2";
     my @refs;
 
@@ -416,8 +430,7 @@ sub parseNARInfo {
         elsif ($1 eq "References") { @refs = split / /, $2; }
         elsif ($1 eq "Deriver") { $deriver = $2; }
         elsif ($1 eq "System") { $system = $2; }
-        elsif ($1 eq "Signature") { $sig = $2; last; }
-        $signedData .= "$line\n";
+        elsif ($1 eq "Sig") { $sig = $2; }
     }
 
     return undef if $storePath ne $storePath2 || !defined $url || !defined $narHash;
@@ -435,16 +448,13 @@ sub parseNARInfo {
         };
 
     if ($requireValidSig) {
+        # FIXME: might be useful to support multiple signatures per .narinfo.
+
         if (!defined $sig) {
             warn "NAR info file ‘$location’ lacks a signature; ignoring\n";
             return undef;
         }
-        my ($sigVersion, $keyName, $sig64) = split ";", $sig;
-        $sigVersion //= 0;
-        if ($sigVersion != 2) {
-            warn "NAR info file ‘$location’ has unsupported version $sigVersion; ignoring\n";
-            return undef;
-        }
+        my ($keyName, $sig64) = split ":", $sig;
         return undef unless defined $keyName && defined $sig64;
 
         my $publicKey = $Nix::Config::binaryCachePublicKeys{$keyName};
@@ -453,10 +463,15 @@ sub parseNARInfo {
             return undef;
         }
 
-        if (!checkSignature($publicKey, decode_base64($sig64), $signedData)) {
+        my $fingerprint = fingerprintPath(
+            $storePath, $narHash,
+            [ map { "$Nix::Config::storeDir/$_" } @refs ]);
+
+        if (!checkSignature($publicKey, decode_base64($sig64), $fingerprint)) {
             warn "NAR info file ‘$location’ has an incorrect signature; ignoring\n";
             return undef;
         }
+
         $res->{signedBy} = $keyName;
     }
 
diff --git a/scripts/nix-push.in b/scripts/nix-push.in
index 0e90ab3c216b..a060ea128fd1 100755
--- a/scripts/nix-push.in
+++ b/scripts/nix-push.in
@@ -257,8 +257,9 @@ for (my $n = 0; $n < scalar @storePaths2; $n++) {
         chomp $s;
         my ($keyName, $secretKey) = split ":", $s;
         die "invalid secret key file ‘$secretKeyFile’\n" unless defined $keyName && defined $secretKey;
-        my $sig = encode_base64(signString(decode_base64($secretKey), $info), "");
-        $info .= "Signature: 2;$keyName;$sig\n";
+        my $fingerprint = fingerprintPath($storePath, $narHash, $refs);
+        my $sig = encode_base64(signString(decode_base64($secretKey), $fingerprint), "");
+        $info .= "Sig: $keyName:$sig\n";
     }
 
     my $pathHash = substr(basename($storePath), 0, 32);