♻️ refactor: extract verify_cert_and_data
							parent
							
								
									0fa43a71d2
								
							
						
					
					
						commit
						026db25ba7
					
				|  | @ -7,6 +7,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <sodium.h> | #include <sodium.h> | ||||||
| 
 | 
 | ||||||
|  | #include "cpp-base64/base64.h" | ||||||
| #include "json.hpp" | #include "json.hpp" | ||||||
| 
 | 
 | ||||||
| #include "string_helpers.h" | #include "string_helpers.h" | ||||||
|  | @ -40,19 +41,18 @@ void try_sodium_init () { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct VerifiedData { | bool is_pubkey_length (const vector <uint8_t> & v) { | ||||||
| 	vector <uint8_t> payload; | 	return v.size () == crypto_sign_PUBLICKEYBYTES; | ||||||
| 	string purpose; | } | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| optional <VerifiedData> try_verify_signed_data ( | optional <vector <uint8_t>> try_verify_signed_data ( | ||||||
| 	const ExpiringSignature & sig, | 	const ExpiringSignature & sig, | ||||||
| 	int64_t now, | 	const vector <uint8_t> & pubkey, | ||||||
| 	const vector <uint8_t> & pubkey | 	int64_t now | ||||||
| ) { | ) { | ||||||
| 	try_sodium_init (); | 	try_sodium_init (); | ||||||
| 	 | 	 | ||||||
| 	if (pubkey.size () != crypto_sign_PUBLICKEYBYTES) { | 	if (! is_pubkey_length (pubkey)) { | ||||||
| 		return nullopt; | 		return nullopt; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|  | @ -77,29 +77,55 @@ optional <VerifiedData> try_verify_signed_data ( | ||||||
| 		return nullopt; | 		return nullopt; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	const string purpose = j ["purpose"]; |  | ||||||
| 	const string payload_b64 = j ["payload_b64"]; | 	const string payload_b64 = j ["payload_b64"]; | ||||||
| 	const auto payload = std::move (*base64_decode (payload_b64)); | 	const auto payload = std::move (*BareMinimumCrypto::base64_decode (payload_b64)); | ||||||
| 	 | 	 | ||||||
| 	return VerifiedData { | 	return payload; | ||||||
| 		payload, |  | ||||||
| 		purpose |  | ||||||
| 	}; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| optional <VerifiedData> verify_signed_data ( | optional <vector <uint8_t>> verify_signed_data ( | ||||||
| 	const ExpiringSignature & sig, | 	const ExpiringSignature & sig, | ||||||
| 	int64_t now, | 	const vector <uint8_t> & pubkey, | ||||||
| 	const vector <uint8_t> & pubkey | 	int64_t now | ||||||
| ) { | ) { | ||||||
| 	try { | 	try { | ||||||
| 		return try_verify_signed_data (sig, now, pubkey); | 		return try_verify_signed_data (sig, pubkey, now); | ||||||
| 	} | 	} | ||||||
| 	catch (json::exception &) { | 	catch (json::exception &) { | ||||||
| 		return nullopt; | 		return nullopt; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | optional <vector <uint8_t>> verify_cert_and_data ( | ||||||
|  | 	const ExpiringSignature & signed_cert, | ||||||
|  | 	const ExpiringSignature & signed_data, | ||||||
|  | 	const vector <uint8_t> & root_pubkey, | ||||||
|  | 	int64_t now | ||||||
|  | ) { | ||||||
|  | 	auto subkey_opt = verify_signed_data (signed_cert, root_pubkey, now); | ||||||
|  | 	if (! subkey_opt) { | ||||||
|  | 		return nullopt; | ||||||
|  | 	} | ||||||
|  | 	const auto subkey = std::move (*subkey_opt); | ||||||
|  | 	 | ||||||
|  | 	return verify_signed_data (signed_data, subkey, now); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | optional <vector <uint8_t>> verify_cert_and_data ( | ||||||
|  | 	const ExpiringSignature & signed_cert, | ||||||
|  | 	const ExpiringSignature & signed_data, | ||||||
|  | 	const vector <uint8_t> & root_pubkey | ||||||
|  | ) { | ||||||
|  | 	return verify_cert_and_data (signed_cert, signed_data, root_pubkey, get_seconds_since_epoch ()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | optional <vector <uint8_t>> verify_signed_data ( | ||||||
|  | 	const ExpiringSignature & sig, | ||||||
|  | 	const vector <uint8_t> & pubkey | ||||||
|  | ) { | ||||||
|  | 	return verify_signed_data (sig, pubkey, get_seconds_since_epoch ()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| class SigningKey { | class SigningKey { | ||||||
| 	vector <uint8_t> pk; | 	vector <uint8_t> pk; | ||||||
| 	vector <uint8_t> sk; | 	vector <uint8_t> sk; | ||||||
|  | @ -123,10 +149,9 @@ public: | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	optional <ExpiringSignature> sign_base64 ( | 	optional <ExpiringSignature> sign_base64 ( | ||||||
| 		const string & payload_b64,  | 		const string & payload_b64, | ||||||
| 		string purpose, | 		int64_t duration, | ||||||
| 		int64_t now, | 		int64_t now | ||||||
| 		int64_t duration |  | ||||||
| 	) const { | 	) const { | ||||||
| 		try_sodium_init (); | 		try_sodium_init (); | ||||||
| 		 | 		 | ||||||
|  | @ -139,7 +164,6 @@ public: | ||||||
| 		const json j { | 		const json j { | ||||||
| 			{"not_before", now}, | 			{"not_before", now}, | ||||||
| 			{"not_after", not_after}, | 			{"not_after", not_after}, | ||||||
| 			{"purpose", purpose}, |  | ||||||
| 			{"payload_b64", payload_b64}, | 			{"payload_b64", payload_b64}, | ||||||
| 		}; | 		}; | ||||||
| 		 | 		 | ||||||
|  | @ -158,15 +182,17 @@ public: | ||||||
| 	 | 	 | ||||||
| 	optional <ExpiringSignature> sign_key (const SigningKey & k, int64_t now) const  | 	optional <ExpiringSignature> sign_key (const SigningKey & k, int64_t now) const  | ||||||
| 	{ | 	{ | ||||||
| 		return sign_base64 (k.pub_to_base64 (), "4QHAB7O5 trusted public key", now, about_3_months); | 		return sign_base64 (k.pub_to_base64 (), about_3_months, now); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	optional <ExpiringSignature> sign_data (const vector <uint8_t> & v, int64_t now) const  | 	optional <ExpiringSignature> sign_data (const vector <uint8_t> & v, int64_t now) const  | ||||||
| 	{ | 	{ | ||||||
| 		return sign_base64 (base64_encode (v), "MS7WL26L signed data", now, about_1_week); | 		return sign_base64 (base64_encode (v), about_1_week, now); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| int happy_path () { | int happy_path () { | ||||||
| 	// We generate a root key and keep it somewhere safe
 | 	// We generate a root key and keep it somewhere safe
 | ||||||
| 	// (offline, hopefully)
 | 	// (offline, hopefully)
 | ||||||
|  | @ -217,43 +243,20 @@ int happy_path () { | ||||||
| 		cerr << base64_encode (cert.sig) << endl; | 		cerr << base64_encode (cert.sig) << endl; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	// The client knows our root public key
 | 	// The receiver verifies the data by the root public key,
 | ||||||
|  | 	// even though the receiver has never seen the sub-key.
 | ||||||
|  | 	 | ||||||
| 	const auto root_pubkey = root_key.pubkey (); | 	const auto root_pubkey = root_key.pubkey (); | ||||||
| 	 | 	auto verified_opt = verify_cert_and_data (cert, signed_data, root_pubkey); | ||||||
| 	{ | 	if (! verified_opt) { | ||||||
| 		auto verified_opt = verify_signed_data (cert, now, root_pubkey); | 		cerr << "Receiver couldn't verify cert and data" << endl; | ||||||
| 		if (! verified_opt) { | 		return 1; | ||||||
| 			cerr << "Couldn't verify cert" << endl; |  | ||||||
| 			return 1; |  | ||||||
| 		} |  | ||||||
| 		const auto verified = std::move (*verified_opt); |  | ||||||
| 		 |  | ||||||
| 		if (verified.purpose != "4QHAB7O5 trusted public key") { |  | ||||||
| 			cerr << "Purpose did not match" << endl; |  | ||||||
| 			return 1; |  | ||||||
| 		} |  | ||||||
| 		if (verified.payload != signing_key.pubkey ()) { |  | ||||||
| 			cerr << "Pubkey payload did not match" << endl; |  | ||||||
| 			return 1; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  | 	const auto verified = std::move (*verified_opt); | ||||||
| 	 | 	 | ||||||
| 	{ | 	if (verified != important_data) { | ||||||
| 		auto verified_opt = verify_signed_data (signed_data, now, signing_key.pubkey ()); | 		cerr << "Verified payload did not match expected payload" << endl; | ||||||
| 		if (! verified_opt) { | 		return 1; | ||||||
| 			cerr << "Couldn't verify cert" << endl; |  | ||||||
| 			return 1; |  | ||||||
| 		} |  | ||||||
| 		const auto verified = std::move (*verified_opt); |  | ||||||
| 		 |  | ||||||
| 		if (verified.purpose != "MS7WL26L signed data") { |  | ||||||
| 			cerr << "Purpose did not match" << endl; |  | ||||||
| 			return 1; |  | ||||||
| 		} |  | ||||||
| 		if (verified.payload != important_data) { |  | ||||||
| 			cerr << "Pubkey payload did not match" << endl; |  | ||||||
| 			return 1; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 _
						_