aboutsummaryrefslogtreecommitdiff
path: root/perl
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-02-04 17:59:31 +0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-02-04 17:59:31 +0100
commitf3a5930488e4a25de33d9aacc2e14ae614614b5e (patch)
tree2001e1e3a2de740642b112ac6385ad3b09dc28ab /perl
parente0def5bc4b41ad09ce3f188bf522814ef3389e1f (diff)
Sign a subset of the .narinfo
We only need to sign the store path, NAR hash and references (the "fingerprint"). Everything else is irrelevant to security. For instance, the compression algorithm or the hash of the compressed NAR don't matter as long as the contents of the uncompressed NAR are correct. (Maybe we should include derivers in the fingerprint, but they're broken and nobody cares about them. Also, it might be nice in the future if .narinfos contained signatures from multiple independent signers. But that's impossible if the deriver is included in the fingerprint, since everybody will tend to have a different deriver for the same store path.) Also renamed the "Signature" field to "Sig" since the format changed in an incompatible way.
Diffstat (limited to 'perl')
-rw-r--r--perl/lib/Nix/Manifest.pm37
1 files changed, 26 insertions, 11 deletions
diff --git a/perl/lib/Nix/Manifest.pm b/perl/lib/Nix/Manifest.pm
index ec3e48fcf..b82c82fb2 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;
}