Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/libstore/binary-cache-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,17 @@ BinaryCacheStore::BinaryCacheStore(const Params & params)
, Store(params)
{
if (secretKeyFile != "")
signer = std::make_unique<LocalSigner>(
SecretKey { readFile(secretKeyFile) });
signers.push_back(std::make_unique<LocalSigner>(
SecretKey { readFile(secretKeyFile) }));

if (secretKeyFiles != "") {
std::stringstream ss(secretKeyFiles);
Path keyPath;
while (std::getline(ss, keyPath, ',')) {
signers.push_back(std::make_unique<LocalSigner>(
SecretKey { readFile(keyPath) }));
}
}

StringSink sink;
sink << narVersionMagic1;
Expand Down Expand Up @@ -270,9 +279,9 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
stats.narWriteCompressedBytes += fileSize;
stats.narWriteCompressionTimeMs += duration;

/* Atomically write the NAR info file.*/
if (signer) narInfo->sign(*this, *signer);
narInfo->sign(*this, signers);

/* Atomically write the NAR info file.*/
writeNarInfo(narInfo);

stats.narInfoWrite++;
Expand Down
5 changes: 4 additions & 1 deletion src/libstore/include/nix/store/binary-cache-store.hh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ struct BinaryCacheStoreConfig : virtual StoreConfig
const Setting<Path> secretKeyFile{this, "", "secret-key",
"Path to the secret key used to sign the binary cache."};

const Setting<std::string> secretKeyFiles{this, "", "secret-keys",
"List of comma-separated paths to the secret keys used to sign the binary cache."};

const Setting<Path> localNarCache{this, "", "local-nar-cache",
"Path to a local cache of NARs fetched from this binary cache, used by commands such as `nix store cat`."};

Expand All @@ -57,7 +60,7 @@ class BinaryCacheStore : public virtual BinaryCacheStoreConfig,
{

private:
std::unique_ptr<Signer> signer;
std::vector<std::unique_ptr<Signer>> signers;

protected:

Expand Down
1 change: 1 addition & 0 deletions src/libstore/include/nix/store/path-info.hh
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ struct ValidPathInfo : UnkeyedValidPathInfo {
std::string fingerprint(const Store & store) const;

void sign(const Store & store, const Signer & signer);
void sign(const Store & store, const std::vector<std::unique_ptr<Signer>> & signers);

/**
* @return The `ContentAddressWithReferences` that determines the
Expand Down
8 changes: 8 additions & 0 deletions src/libstore/path-info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ void ValidPathInfo::sign(const Store & store, const Signer & signer)
sigs.insert(signer.signDetached(fingerprint(store)));
}

void ValidPathInfo::sign(const Store & store, const std::vector<std::unique_ptr<Signer>> & signers)
{
auto fingerprint = this->fingerprint(store);
for (auto & signer: signers) {
sigs.insert(signer->signDetached(fingerprint));
}
}

std::optional<ContentAddressWithReferences> ValidPathInfo::contentAddressWithReferences() const
{
if (! ca)
Expand Down
10 changes: 10 additions & 0 deletions tests/functional/signing.sh
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,13 @@ nix store verify --store "$TEST_ROOT"/store0 -r "$outPath2" --trusted-public-key

# Content-addressed stuff can be copied without signatures.
nix copy --to "$TEST_ROOT"/store0 "$outPathCA"

# Test multiple signing keys
nix copy --to "file://$TEST_ROOT/storemultisig?secret-keys=$TEST_ROOT/sk1,$TEST_ROOT/sk2" "$outPath"
for file in "$TEST_ROOT/storemultisig/"*.narinfo; do
if [[ "$(grep -cE '^Sig: cache[1,2]\.example.org' "$file")" -ne 2 ]]; then
echo "ERROR: Cannot find cache1.example.org and cache2.example.org signatures in ${file}"
cat "${file}"
exit 1
fi
done
Loading