The name had become a misnomer since it's not only for substitution from binary caches, but when adding/copying any (non-content-addressed) path to a store.
		
			
				
	
	
		
			126 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			126 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.trustedPublicKeys.get()) {
 | 
						|
        PublicKey key(s);
 | 
						|
        publicKeys.emplace(key.name, key);
 | 
						|
    }
 | 
						|
 | 
						|
    for (auto secretKeyFile : settings.secretKeyFiles.get()) {
 | 
						|
        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;
 | 
						|
}
 | 
						|
 | 
						|
}
 |