From 46e0919ced4646004cc0701b188d0a68e24e8924 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 21 Feb 2007 14:31:42 +0000 Subject: [PATCH] * `nix-store --export --sign': sign the Nix archive using the RSA key in /nix/etc/nix/signing-key.sec --- doc/signing.txt | 4 +-- src/libstore/build.cc | 3 +- src/libstore/local-store.cc | 64 ++++++++++++++++++++++++++++++++++--- src/libutil/hash.cc | 39 +++++++++++++--------- src/libutil/hash.hh | 19 ++++++++++- src/libutil/util.cc | 15 +++++++-- src/libutil/util.hh | 3 +- src/nix-store/nix-store.cc | 10 ++++-- 8 files changed, 125 insertions(+), 32 deletions(-) diff --git a/doc/signing.txt b/doc/signing.txt index fad14d743..1d042e95e 100644 --- a/doc/signing.txt +++ b/doc/signing.txt @@ -1,6 +1,6 @@ Generate a private key: -$ openssl genrsa -out mykey.sec 2048 +$ (umask 277 && openssl genrsa -out /nix/etc/nix/signing-key.sec 2048) The private key should be kept secret (only readable to the Nix daemon user). @@ -8,7 +8,7 @@ user). Generate the corresponding public key: -$ openssl rsa -in mykey.sec -pubout > mykey.pub +$ openssl rsa -in /nix/etc/nix/signing-key.sec -pubout > /nix/etc/nix/signing-key.pub The public key should be copied to all machines to which you want to export store paths. diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 1789eeda2..bee046655 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -477,8 +477,7 @@ static void runSetuidHelper(const string & command, case 0: /* child */ try { - std::vector args; /* careful with c_str()! - */ + std::vector args; /* careful with c_str()! */ args.push_back(program.c_str()); args.push_back(command.c_str()); args.push_back(arg.c_str()); diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index dcb430a0f..991f28e8d 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -696,21 +696,75 @@ Path LocalStore::addTextToStore(const string & suffix, const string & s, } +struct HashAndWriteSink : Sink +{ + Sink & writeSink; + HashSink hashSink; + bool hashing; + HashAndWriteSink(Sink & writeSink) : writeSink(writeSink), hashSink(htSHA256) + { + hashing = true; + } + virtual void operator () + (const unsigned char * data, unsigned int len) + { + writeSink(data, len); + if (hashing) hashSink(data, len); + } +}; + + +#define EXPORT_MAGIC 0x4558494e + + void LocalStore::exportPath(const Path & path, bool sign, Sink & sink) { assertStorePath(path); - - dumpPath(path, sink); - writeString(path, sink); + HashAndWriteSink hashAndWriteSink(sink); + + dumpPath(path, hashAndWriteSink); + + writeInt(EXPORT_MAGIC, hashAndWriteSink); + + writeString(path, hashAndWriteSink); PathSet references; queryReferences(path, references); - writeStringSet(references, sink); + writeStringSet(references, hashAndWriteSink); Path deriver = queryDeriver(noTxn, path); - writeString(deriver, sink); + writeString(deriver, hashAndWriteSink); + + if (sign) { + Hash hash = hashAndWriteSink.hashSink.finish(); + hashAndWriteSink.hashing = false; + + writeInt(1, hashAndWriteSink); + + //printMsg(lvlError, format("HASH = %1%") % printHash(hash)); + + Path tmpDir = createTempDir(); + AutoDelete delTmp(tmpDir); + Path hashFile = tmpDir + "/hash"; + writeStringToFile(hashFile, printHash(hash)); + + Strings args; + args.push_back("rsautl"); + args.push_back("-sign"); + args.push_back("-inkey"); + args.push_back(nixConfDir + "/signing-key.sec"); + args.push_back("-in"); + args.push_back(hashFile); + string signature = runProgram("openssl", true, args); + + //printMsg(lvlError, format("SIGNATURE = %1%") % signature); + + writeString(signature, hashAndWriteSink); + + } else + writeInt(0, hashAndWriteSink); } diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc index 262dbef20..3d20d2d50 100644 --- a/src/libutil/hash.cc +++ b/src/libutil/hash.cc @@ -282,27 +282,36 @@ Hash hashFile(HashType ht, const Path & path) } -struct HashSink : Sink +HashSink::HashSink(HashType ht) : ht(ht) { - HashType ht; - Ctx ctx; - virtual void operator () - (const unsigned char * data, unsigned int len) - { - update(ht, ctx, data, len); - } -}; + ctx = new Ctx; + start(ht, *ctx); +} + +HashSink::~HashSink() +{ + delete ctx; +} + +void HashSink::operator () + (const unsigned char * data, unsigned int len) +{ + update(ht, *ctx, data, len); +} + +Hash HashSink::finish() +{ + Hash hash(ht); + nix::finish(ht, *ctx, hash.hash); + return hash; +} Hash hashPath(HashType ht, const Path & path, PathFilter & filter) { - HashSink sink; - sink.ht = ht; - Hash hash(ht); - start(ht, sink.ctx); + HashSink sink(ht); dumpPath(path, sink, filter); - finish(ht, sink.ctx, hash.hash); - return hash; + return sink.finish(); } diff --git a/src/libutil/hash.hh b/src/libutil/hash.hh index 78227fb6a..85eb3c1b4 100644 --- a/src/libutil/hash.hh +++ b/src/libutil/hash.hh @@ -2,6 +2,7 @@ #define __HASH_H #include "types.hh" +#include "serialise.hh" namespace nix { @@ -81,7 +82,23 @@ Hash compressHash(const Hash & hash, unsigned int newSize); /* Parse a string representing a hash type. */ HashType parseHashType(const string & s); - + +typedef union Ctx; + +class HashSink : public Sink +{ +private: + HashType ht; + Ctx * ctx; + +public: + HashSink(HashType ht); + ~HashSink(); + virtual void operator () (const unsigned char * data, unsigned int len); + Hash finish(); +}; + + } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index fb6411408..7671c7c7e 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -761,7 +761,7 @@ void killUser(uid_t uid) ////////////////////////////////////////////////////////////////////// -string runProgram(Path program) +string runProgram(Path program, bool searchPath, const Strings & args) { /* Create a pipe. */ Pipe pipe; @@ -781,8 +781,17 @@ string runProgram(Path program) if (dup2(pipe.writeSide, STDOUT_FILENO) == -1) throw SysError("dupping from-hook write side"); - - execl(program.c_str(), program.c_str(), (char *) 0); + + std::vector cargs; /* careful with c_str()! */ + cargs.push_back(program.c_str()); + for (Strings::const_iterator i = args.begin(); i != args.end(); ++i) + cargs.push_back(i->c_str()); + cargs.push_back(0); + + if (searchPath) + execvp(program.c_str(), (char * *) &cargs[0]); + else + execv(program.c_str(), (char * *) &cargs[0]); throw SysError(format("executing `%1%'") % program); } catch (std::exception & e) { diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 1cc97145c..0ebf6f5a5 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -231,7 +231,8 @@ void killUser(uid_t uid); /* Run a program and return its stdout in a string (i.e., like the shell backtick operator). */ -string runProgram(Path program); +string runProgram(Path program, bool searchPath = false, + const Strings & args = Strings()); /* Wrapper around _exit() on Unix and ExitProcess() on Windows. (On Cygwin, _exit() doesn't seem to do the right thing.) */ diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 821124324..7b56de7e4 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -640,10 +640,14 @@ static void opRestore(Strings opFlags, Strings opArgs) static void opExport(Strings opFlags, Strings opArgs) { - if (!opFlags.empty()) throw UsageError("unknown flag"); - + bool sign = false; + for (Strings::iterator i = opFlags.begin(); + i != opFlags.end(); ++i) + if (*i == "--sign") sign = true; + else throw UsageError(format("unknown flag `%1%'") % *i); + FdSink sink(STDOUT_FILENO); - store->exportPath(*opArgs.begin(), false, sink); + store->exportPath(*opArgs.begin(), sign, sink); }