From 09136ef04614cc49025dfaf116db3256edf5bf46 Mon Sep 17 00:00:00 2001
From: Mirek Kratochvil <exa.exa@gmail.com>
Date: Thu, 12 Sep 2013 12:41:54 +0200
Subject: [PATCH] actions: better keyring opening behavior

This delays opening (and locking) the keyring until all input has been
processed, and all possible errors that would make a chance that the
keyring doesn't have to be opened have been checked for.

Whole purpose was to enable codecrypt to be chained with pipes in UNIX-y way,
like this primitive certificate creation:

(echo "At `date` I certify this is The Key:" ; ccr -pa -F "the key") | ccr -s
---
 src/actions.cpp | 73 +++++++++++++++++++++++++++++++++++++++++--------
 src/main.cpp    |  6 ----
 2 files changed, 61 insertions(+), 18 deletions(-)

diff --git a/src/actions.cpp b/src/actions.cpp
index 795370c..093539b 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -38,6 +38,17 @@
 #define MSG_CLEARTEXT "MESSAGE-IN-CLEARTEXT"
 #define MSG_DETACHED "MESSAGE-DETACHED"
 
+inline bool open_keyring (keyring&KR)
+{
+	if (!KR.open() ) {
+		err ("could not open keyring!");
+		return false;
+	}
+	return true;
+}
+
+#define PREPARE_KEYRING if(!open_keyring(KR)) return 1
+
 int action_gen_key (const std::string& algspec, const std::string&name,
                     keyring&KR, algorithm_suite&AS)
 {
@@ -96,6 +107,8 @@ int action_gen_key (const std::string& algspec, const std::string&name,
 		return 1;
 	}
 
+	PREPARE_KEYRING;
+
 	//TODO this can fail, handle it.
 	KR.store_keypair (keyring::get_keyid (pub), name, algname, pub, priv);
 	//pub&priv data will get destroyed along with keyring
@@ -115,9 +128,15 @@ int action_gen_key (const std::string& algspec, const std::string&name,
 int action_encrypt (const std::string&recipient, bool armor,
                     keyring&KR, algorithm_suite&AS)
 {
-	//first, find a recipient
+	//first, read plaintext
+	std::string data;
+	read_all_input (data);
+
+	//find a recipient
 	keyring::pubkey_entry *recip = NULL;
 
+	PREPARE_KEYRING;
+
 	//search both publickeys and keypairs that are valid for encryption
 	for (keyring::pubkey_storage::iterator
 	     i = KR.pubs.begin(), e = KR.pubs.end(); i != e; ++i) {
@@ -152,10 +171,7 @@ int action_encrypt (const std::string&recipient, bool armor,
 		return 1;
 	}
 
-	//read plaintext
-	std::string data;
-	read_all_input (data);
-
+	//encryption part
 	encrypted_msg msg;
 	arcfour_rng r;
 	r.seed (256);
@@ -223,6 +239,8 @@ int action_decrypt (bool armor,
 
 	sencode_destroy (M);
 
+	PREPARE_KEYRING;
+
 	//check if we have the privkey
 	keyring::keypair_entry*kpe;
 	kpe = KR.get_keypair (msg.key_id);
@@ -312,6 +330,12 @@ int action_sign (const std::string&user, bool armor, const std::string&detach,
 		}
 	}
 
+	//eat data for signature
+	std::string data;
+	read_all_input (data);
+
+	PREPARE_KEYRING;
+
 	//some common checks on user key
 	keyring::keypair_entry *u = NULL;
 
@@ -340,10 +364,7 @@ int action_sign (const std::string&user, bool armor, const std::string&detach,
 		return 1;
 	}
 
-	//eat data
-	std::string data;
-	read_all_input (data);
-
+	//signature production part
 	signed_msg msg;
 	arcfour_rng r;
 	r.seed (256);
@@ -583,6 +604,8 @@ int action_verify (bool armor, const std::string&detach,
 		return 1;
 	}
 
+	PREPARE_KEYRING;
+
 	//check pubkey availability
 	keyring::pubkey_entry*pke;
 	pke = KR.get_pubkey (msg.key_id);
@@ -653,6 +676,12 @@ int action_sign_encrypt (const std::string&user, const std::string&recipient,
 	 * (it would leak the information that inner message is signed).
 	 */
 
+	//eat al input first
+	std::string data;
+	read_all_input (data);
+
+	PREPARE_KEYRING;
+
 	//find some good local user
 	keyring::keypair_entry *u = NULL;
 
@@ -712,9 +741,6 @@ int action_sign_encrypt (const std::string&user, const std::string&recipient,
 	}
 
 	//make a signature
-	std::string data;
-	read_all_input (data);
-
 	signed_msg smsg;
 	arcfour_rng r;
 	r.seed (256);
@@ -794,6 +820,8 @@ int action_decrypt_verify (bool armor, bool yes,
 
 	sencode_destroy (M);
 
+	PREPARE_KEYRING;
+
 	//check if we will be able to decrypt
 	keyring::keypair_entry*kpe;
 	kpe = KR.get_keypair (emsg.key_id);
@@ -936,6 +964,8 @@ static void output_key (bool fp,
 int action_list (bool nice_fingerprint, const std::string&filter,
                  keyring&KR)
 {
+	PREPARE_KEYRING;
+
 	for (keyring::keypair_storage::iterator
 	     i = KR.pairs.begin(), e = KR.pairs.end();
 	     i != e; ++i) {
@@ -1019,6 +1049,8 @@ int action_import (bool armor, bool no_action, bool yes, bool fp,
 		return 0;
 	}
 
+	PREPARE_KEYRING;
+
 	//informatively count how much stuff is this going to destroy.
 	int rewrites = 0, privs = 0;
 	for (keyring::pubkey_storage::iterator
@@ -1068,6 +1100,8 @@ int action_export (bool armor,
                    const std::string & filter, const std::string & name,
                    keyring & KR)
 {
+	PREPARE_KEYRING;
+
 	keyring::pubkey_storage s;
 
 	for (keyring::keypair_storage::iterator
@@ -1117,6 +1151,8 @@ int action_export (bool armor,
 
 int action_delete (bool yes, const std::string & filter, keyring & KR)
 {
+	PREPARE_KEYRING;
+
 	int kc = 0;
 	for (keyring::pubkey_storage::iterator
 	     i = KR.pubs.begin(), e = KR.pubs.end();
@@ -1165,6 +1201,9 @@ int action_rename (bool yes,
 		err ("error: missing new name specification");
 		return 1;
 	}
+
+	PREPARE_KEYRING;
+
 	int kc = 0;
 	for (keyring::pubkey_storage::iterator
 	     i = KR.pubs.begin(), e = KR.pubs.end();
@@ -1205,6 +1244,8 @@ int action_rename (bool yes,
 int action_list_sec (bool nice_fingerprint, const std::string & filter,
                      keyring & KR)
 {
+	PREPARE_KEYRING;
+
 	for (keyring::keypair_storage::iterator
 	     i = KR.pairs.begin(), e = KR.pairs.end();
 	     i != e; ++i) {
@@ -1277,6 +1318,8 @@ int action_import_sec (bool armor, bool no_action, bool yes, bool fp,
 		return 0;
 	}
 
+	PREPARE_KEYRING;
+
 	int rewrites = 0;
 	for (keyring::keypair_storage::iterator
 	     i = s.begin(), e = s.end(); i != e; ++i) {
@@ -1321,6 +1364,8 @@ int action_export_sec (bool armor, bool yes,
                        const std::string & filter, const std::string & name,
                        keyring & KR)
 {
+	PREPARE_KEYRING;
+
 	keyring::keypair_storage s;
 	for (keyring::keypair_storage::iterator
 	     i = KR.pairs.begin(), e = KR.pairs.end();
@@ -1366,6 +1411,8 @@ int action_export_sec (bool armor, bool yes,
 
 int action_delete_sec (bool yes, const std::string & filter, keyring & KR)
 {
+	PREPARE_KEYRING;
+
 	int kc = 0;
 	for (keyring::keypair_storage::iterator
 	     i = KR.pairs.begin(), e = KR.pairs.end();
@@ -1415,6 +1462,8 @@ int action_rename_sec (bool yes,
 		return 1;
 	}
 
+	PREPARE_KEYRING;
+
 	int kc = 0;
 	for (keyring::keypair_storage::iterator
 	     i = KR.pairs.begin(), e = KR.pairs.end();
diff --git a/src/main.cpp b/src/main.cpp
index df0bfd3..022a4d5 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -386,12 +386,6 @@ int main (int argc, char**argv)
 	keyring KR;
 	algorithm_suite AS;
 
-	//keyring initialization
-	if (!KR.open() ) {
-		progerr ("could not open keyring!");
-		return 1;
-	}
-
 	//register all available algorithms
 	fill_algorithm_suite (AS);