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.get("binary-cache-public-keys", Strings())) {
 | |
|         PublicKey key(s);
 | |
|         publicKeys.emplace(key.name, key);
 | |
|     }
 | |
| 
 | |
|     for (auto secretKeyFile : settings.get("secret-key-files", Strings())) {
 | |
|         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;
 | |
| }
 | |
| 
 | |
| }
 |