about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-02-04T15·43+0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-02-04T16·10+0100
commite0def5bc4b41ad09ce3f188bf522814ef3389e1f (patch)
tree70b894e41d8b682a166872d28d720e438aea8dda /src
parent0d1dafa0c4ef8adc27315653df8a170c0cf33985 (diff)
Use libsodium instead of OpenSSL for binary cache signing
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.
Diffstat (limited to 'src')
-rw-r--r--src/libutil/util.cc25
-rw-r--r--src/libutil/util.hh2
-rw-r--r--src/nix-store/local.mk2
-rw-r--r--src/nix-store/nix-store.cc34
4 files changed, 53 insertions, 10 deletions
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<const char *> 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<void()> 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 <bzlib.h>
 
+#include <sodium.h>
+
 
 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 */