From e0def5bc4b41ad09ce3f188bf522814ef3389e1f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 4 Feb 2015 16:43:32 +0100 Subject: Use libsodium instead of OpenSSL for binary cache signing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sodium's Ed25519 signatures are much shorter than OpenSSL's RSA signatures. Public keys are also much shorter, so they're now specified directly in the nix.conf option ‘binary-cache-public-keys’. The new command ‘nix-store --generate-binary-cache-key’ generates and prints a public and secret key. --- src/libutil/util.cc | 25 +++++++++++++++++++------ src/libutil/util.hh | 2 +- src/nix-store/local.mk | 2 +- src/nix-store/nix-store.cc | 34 ++++++++++++++++++++++++++++++++-- 4 files changed, 53 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 0d903f2f0d43..4f3010880286 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -925,18 +925,24 @@ std::vector stringsToCharPtrs(const Strings & ss) } -string runProgram(Path program, bool searchPath, const Strings & args) +string runProgram(Path program, bool searchPath, const Strings & args, + const string & input) { checkInterrupt(); /* Create a pipe. */ - Pipe pipe; - pipe.create(); + Pipe stdout, stdin; + stdout.create(); + if (!input.empty()) stdin.create(); /* Fork. */ Pid pid = startProcess([&]() { - if (dup2(pipe.writeSide, STDOUT_FILENO) == -1) + if (dup2(stdout.writeSide, STDOUT_FILENO) == -1) throw SysError("dupping stdout"); + if (!input.empty()) { + if (dup2(stdin.readSide, STDIN_FILENO) == -1) + throw SysError("dupping stdin"); + } Strings args_(args); args_.push_front(program); @@ -950,9 +956,16 @@ string runProgram(Path program, bool searchPath, const Strings & args) throw SysError(format("executing ‘%1%’") % program); }); - pipe.writeSide.close(); + stdout.writeSide.close(); + + /* FIXME: This can deadlock if the input is too long. */ + if (!input.empty()) { + stdin.readSide.close(); + writeFull(stdin.writeSide, input); + stdin.writeSide.close(); + } - string result = drainFD(pipe.readSide); + string result = drainFD(stdout.readSide); /* Wait for the child to finish. */ int status = pid.wait(true); diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 186ee71f45d0..1a2dda527121 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -285,7 +285,7 @@ pid_t startProcess(std::function fun, const ProcessOptions & options = P /* Run a program and return its stdout in a string (i.e., like the shell backtick operator). */ string runProgram(Path program, bool searchPath = false, - const Strings & args = Strings()); + const Strings & args = Strings(), const string & input = ""); MakeError(ExecError, Error) diff --git a/src/nix-store/local.mk b/src/nix-store/local.mk index b887fe03389b..84ff15b241f3 100644 --- a/src/nix-store/local.mk +++ b/src/nix-store/local.mk @@ -6,6 +6,6 @@ nix-store_SOURCES := $(wildcard $(d)/*.cc) nix-store_LIBS = libmain libstore libutil libformat -nix-store_LDFLAGS = -lbz2 -pthread +nix-store_LDFLAGS = -lbz2 -pthread $(SODIUM_LIBS) nix-store_CXXFLAGS = -DCURL=\"$(curl)\" diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 87bc8c379de5..18739736838e 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -20,6 +20,8 @@ #include +#include + using namespace nix; using std::cin; @@ -1006,6 +1008,32 @@ static void opServe(Strings opFlags, Strings opArgs) } +static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs) +{ + foreach (Strings::iterator, i, opFlags) + throw UsageError(format("unknown flag ‘%1%’") % *i); + + if (opArgs.size() != 1) throw UsageError("one argument expected"); + string keyName = opArgs.front(); + + sodium_init(); + + unsigned char pk[crypto_sign_PUBLICKEYBYTES]; + unsigned char sk[crypto_sign_SECRETKEYBYTES]; + if (crypto_sign_keypair(pk, sk) != 0) + throw Error("key generation failed"); + + // FIXME: super ugly way to do base64 encoding. + auto args = Strings({"-MMIME::Base64", "-0777", "-ne", "print encode_base64($_, '')"}); + + string pk64 = runProgram("perl", true, args, string((char *) pk, crypto_sign_PUBLICKEYBYTES)); + std::cout << keyName << ":" << pk64 << std::endl; + + string sk64 = runProgram("perl", true, args, string((char *) sk, crypto_sign_SECRETKEYBYTES)); + std::cout << keyName << ":" << sk64 << std::endl; +} + + /* Scan the arguments; find the operation, set global flags, put all other flags in a list, and put all other arguments in another list. */ @@ -1072,14 +1100,16 @@ int main(int argc, char * * argv) op = opQueryFailedPaths; else if (*arg == "--clear-failed-paths") op = opClearFailedPaths; + else if (*arg == "--serve") + op = opServe; + else if (*arg == "--generate-binary-cache-key") + op = opGenerateBinaryCacheKey; else if (*arg == "--add-root") gcRoot = absPath(getArg(*arg, arg, end)); else if (*arg == "--indirect") indirectRoot = true; else if (*arg == "--no-output") noOutput = true; - else if (*arg == "--serve") - op = opServe; else if (*arg != "" && arg->at(0) == '-') { opFlags.push_back(*arg); if (*arg == "--max-freed" || *arg == "--max-links" || *arg == "--max-atime") /* !!! hack */ -- cgit 1.4.1