forked from lix-project/lix
e7cb2847ab
Previously, the Settings class allowed other code to query for string properties, which led to a proliferation of code all over the place making up new options without any sort of central registry of valid options. This commit pulls all those options back into the central Settings class and removes the public get() methods, to discourage future abuses like that. Furthermore, because we know the full set of options ahead of time, we now fail loudly if someone enters an unrecognized option, thus preventing subtle typos. With some template fun, we could probably also dump the full set of options (with documentation, defaults, etc.) to the command line, but I'm not doing that yet here.
127 lines
2.9 KiB
C++
127 lines
2.9 KiB
C++
#include "crypto.hh"
|
|
#include "util.hh"
|
|
#include "globals.hh"
|
|
|
|
#if HAVE_SODIUM
|
|
#include <sodium.h>
|
|
#endif
|
|
|
|
namespace nix {
|
|
|
|
static std::pair<std::string, std::string> split(const string & s)
|
|
{
|
|
size_t colon = s.find(':');
|
|
if (colon == std::string::npos || colon == 0)
|
|
return {"", ""};
|
|
return {std::string(s, 0, colon), std::string(s, colon + 1)};
|
|
}
|
|
|
|
Key::Key(const string & s)
|
|
{
|
|
auto ss = split(s);
|
|
|
|
name = ss.first;
|
|
key = ss.second;
|
|
|
|
if (name == "" || key == "")
|
|
throw Error("secret key is corrupt");
|
|
|
|
key = base64Decode(key);
|
|
}
|
|
|
|
SecretKey::SecretKey(const string & s)
|
|
: Key(s)
|
|
{
|
|
#if HAVE_SODIUM
|
|
if (key.size() != crypto_sign_SECRETKEYBYTES)
|
|
throw Error("secret key is not valid");
|
|
#endif
|
|
}
|
|
|
|
#if !HAVE_SODIUM
|
|
[[noreturn]] static void noSodium()
|
|
{
|
|
throw Error("Nix was not compiled with libsodium, required for signed binary cache support");
|
|
}
|
|
#endif
|
|
|
|
std::string SecretKey::signDetached(const std::string & data) const
|
|
{
|
|
#if HAVE_SODIUM
|
|
unsigned char sig[crypto_sign_BYTES];
|
|
unsigned long long sigLen;
|
|
crypto_sign_detached(sig, &sigLen, (unsigned char *) data.data(), data.size(),
|
|
(unsigned char *) key.data());
|
|
return name + ":" + base64Encode(std::string((char *) sig, sigLen));
|
|
#else
|
|
noSodium();
|
|
#endif
|
|
}
|
|
|
|
PublicKey SecretKey::toPublicKey() const
|
|
{
|
|
#if HAVE_SODIUM
|
|
unsigned char pk[crypto_sign_PUBLICKEYBYTES];
|
|
crypto_sign_ed25519_sk_to_pk(pk, (unsigned char *) key.data());
|
|
return PublicKey(name, std::string((char *) pk, crypto_sign_PUBLICKEYBYTES));
|
|
#else
|
|
noSodium();
|
|
#endif
|
|
}
|
|
|
|
PublicKey::PublicKey(const string & s)
|
|
: Key(s)
|
|
{
|
|
#if HAVE_SODIUM
|
|
if (key.size() != crypto_sign_PUBLICKEYBYTES)
|
|
throw Error("public key is not valid");
|
|
#endif
|
|
}
|
|
|
|
bool verifyDetached(const std::string & data, const std::string & sig,
|
|
const PublicKeys & publicKeys)
|
|
{
|
|
#if HAVE_SODIUM
|
|
auto ss = split(sig);
|
|
|
|
auto key = publicKeys.find(ss.first);
|
|
if (key == publicKeys.end()) return false;
|
|
|
|
auto sig2 = base64Decode(ss.second);
|
|
if (sig2.size() != crypto_sign_BYTES)
|
|
throw Error("signature is not valid");
|
|
|
|
return crypto_sign_verify_detached((unsigned char *) sig2.data(),
|
|
(unsigned char *) data.data(), data.size(),
|
|
(unsigned char *) key->second.key.data()) == 0;
|
|
#else
|
|
noSodium();
|
|
#endif
|
|
}
|
|
|
|
PublicKeys getDefaultPublicKeys()
|
|
{
|
|
PublicKeys publicKeys;
|
|
|
|
// FIXME: filter duplicates
|
|
|
|
for (auto s : settings.binaryCachePublicKeys) {
|
|
PublicKey key(s);
|
|
publicKeys.emplace(key.name, key);
|
|
}
|
|
|
|
for (auto secretKeyFile : settings.secretKeyFiles) {
|
|
try {
|
|
SecretKey secretKey(readFile(secretKeyFile));
|
|
publicKeys.emplace(secretKey.name, secretKey.toPublicKey());
|
|
} catch (SysError & e) {
|
|
/* Ignore unreadable key files. That's normal in a
|
|
multi-user installation. */
|
|
}
|
|
}
|
|
|
|
return publicKeys;
|
|
}
|
|
|
|
}
|