verify: Add an option to dump a specific message in the format that its signature validates as well as a hex representation of the bytes for good measure.
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Build Tilde Friends / Build-All (push) Successful in 31m2s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Build Tilde Friends / Build-All (push) Successful in 31m2s
				
			This commit is contained in:
		| @@ -13,6 +13,9 @@ | ||||
|  | ||||
| #include "quickjs.h" | ||||
|  | ||||
| /** | ||||
| ** An HTTP server instance. | ||||
| */ | ||||
| typedef struct _tf_http_t tf_http_t; | ||||
|  | ||||
| /** | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/main.c
									
									
									
									
									
								
							| @@ -1161,17 +1161,19 @@ static int _tf_command_verify(const char* file, int argc, char* argv[]) | ||||
| 	const char* identity = NULL; | ||||
| 	const char* default_db_path = _get_db_path(); | ||||
| 	const char* db_path = default_db_path; | ||||
| 	int64_t sequence = 0; | ||||
| 	bool show_usage = false; | ||||
|  | ||||
| 	while (!show_usage) | ||||
| 	{ | ||||
| 		static const struct option k_options[] = { | ||||
| 			{ "id", required_argument, NULL, 'i' }, | ||||
| 			{ "sequence", required_argument, NULL, 's' }, | ||||
| 			{ "db-path", required_argument, NULL, 'd' }, | ||||
| 			{ "help", no_argument, NULL, 'h' }, | ||||
| 			{ 0 }, | ||||
| 		}; | ||||
| 		int c = getopt_long(argc, argv, "i:d:h", k_options, NULL); | ||||
| 		int c = getopt_long(argc, argv, "i:s:d:h", k_options, NULL); | ||||
| 		if (c == -1) | ||||
| 		{ | ||||
| 			break; | ||||
| @@ -1187,6 +1189,9 @@ static int _tf_command_verify(const char* file, int argc, char* argv[]) | ||||
| 		case 'i': | ||||
| 			identity = optarg; | ||||
| 			break; | ||||
| 		case 's': | ||||
| 			sequence = atoll(optarg); | ||||
| 			break; | ||||
| 		case 'd': | ||||
| 			db_path = optarg; | ||||
| 			break; | ||||
| @@ -1198,6 +1203,7 @@ static int _tf_command_verify(const char* file, int argc, char* argv[]) | ||||
| 		tf_printf("\n%s import [options] [paths...]\n\n", file); | ||||
| 		tf_printf("options:\n"); | ||||
| 		tf_printf("  -i, --identity identity  Identity to verify.\n"); | ||||
| 		tf_printf("  -s, --sequence sequence  Sequence number to debug.\n"); | ||||
| 		tf_printf("  -d, --db-path db_path    SQLite database path (default: %s).\n", default_db_path); | ||||
| 		tf_printf("  -h, --help               Show this usage information.\n"); | ||||
| 		tf_free((void*)default_db_path); | ||||
| @@ -1209,7 +1215,7 @@ static int _tf_command_verify(const char* file, int argc, char* argv[]) | ||||
| 	if (identity) | ||||
| 	{ | ||||
| 		tf_printf("Verifying %s...\n", identity); | ||||
| 		verified = tf_ssb_db_verify(ssb, identity, true); | ||||
| 		verified = tf_ssb_db_verify(ssb, identity, sequence, true); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -1222,7 +1228,7 @@ static int _tf_command_verify(const char* file, int argc, char* argv[]) | ||||
| 			{ | ||||
| 				const char* identity = (const char*)sqlite3_column_text(statement, 0); | ||||
| 				tf_printf("Verifying %s...", identity); | ||||
| 				if (tf_ssb_db_verify(ssb, identity, true)) | ||||
| 				if (tf_ssb_db_verify(ssb, identity, sequence, true)) | ||||
| 				{ | ||||
| 					tf_printf("success.\n"); | ||||
| 				} | ||||
|   | ||||
							
								
								
									
										22
									
								
								src/ssb.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/ssb.c
									
									
									
									
									
								
							| @@ -1076,7 +1076,8 @@ void tf_ssb_calculate_message_id(JSContext* context, JSValue message, char* out_ | ||||
| 	JS_FreeValue(context, idval); | ||||
| } | ||||
|  | ||||
| static bool _tf_ssb_verify_and_strip_signature_internal(JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size) | ||||
| static bool _tf_ssb_verify_and_strip_signature_internal( | ||||
| 	JSContext* context, JSValue val, int verify_flags, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size) | ||||
| { | ||||
| 	JSValue signature = JS_GetPropertyStr(context, val, "signature"); | ||||
| 	if (JS_IsUndefined(signature)) | ||||
| @@ -1124,6 +1125,16 @@ static bool _tf_ssb_verify_and_strip_signature_internal(JSContext* context, JSVa | ||||
| 		{ | ||||
| 			r = crypto_sign_verify_detached(binsig, (const uint8_t*)sigstr, strlen(sigstr), publickey); | ||||
| 			verified = r == 0; | ||||
| 			if (verify_flags & k_tf_ssb_verify_flag_debug) | ||||
| 			{ | ||||
| 				tf_printf("verifying author=%s id=%s signature=%s success=%d\n", author, out_id, str, verified); | ||||
| 				tf_printf("signed string:\n%s\n\n", sigstr); | ||||
| 				for (int i = 0; sigstr[i]; i++) | ||||
| 				{ | ||||
| 					tf_printf("%s%02x", (i && (i % 32) == 0) ? "\n" : (i && (i % 8) == 0) ? "  " : (i ? " " : ""), sigstr[i]); | ||||
| 				} | ||||
| 				tf_printf("\n"); | ||||
| 			} | ||||
| 			if (!verified) | ||||
| 			{ | ||||
| 				// tf_printf("crypto_sign_verify_detached fail (r=%d)\n", r); | ||||
| @@ -1161,7 +1172,8 @@ static bool _tf_ssb_verify_and_strip_signature_internal(JSContext* context, JSVa | ||||
| 	return verified; | ||||
| } | ||||
|  | ||||
| bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, int* out_flags) | ||||
| bool tf_ssb_verify_and_strip_signature( | ||||
| 	JSContext* context, JSValue val, int verify_flags, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, int* out_flags) | ||||
| { | ||||
| 	JSValue reordered = JS_NewObject(context); | ||||
| 	JS_SetPropertyStr(context, reordered, "previous", JS_GetPropertyStr(context, val, "previous")); | ||||
| @@ -1171,7 +1183,7 @@ bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* ou | ||||
| 	JS_SetPropertyStr(context, reordered, "hash", JS_GetPropertyStr(context, val, "hash")); | ||||
| 	JS_SetPropertyStr(context, reordered, "content", JS_GetPropertyStr(context, val, "content")); | ||||
| 	JS_SetPropertyStr(context, reordered, "signature", JS_GetPropertyStr(context, val, "signature")); | ||||
| 	bool result = _tf_ssb_verify_and_strip_signature_internal(context, reordered, out_id, out_id_size, out_signature, out_signature_size); | ||||
| 	bool result = _tf_ssb_verify_and_strip_signature_internal(context, reordered, verify_flags, out_id, out_id_size, out_signature, out_signature_size); | ||||
| 	JS_FreeValue(context, reordered); | ||||
|  | ||||
| 	if (result) | ||||
| @@ -1191,7 +1203,7 @@ bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* ou | ||||
| 	JS_SetPropertyStr(context, reordered, "hash", JS_GetPropertyStr(context, val, "hash")); | ||||
| 	JS_SetPropertyStr(context, reordered, "content", JS_GetPropertyStr(context, val, "content")); | ||||
| 	JS_SetPropertyStr(context, reordered, "signature", JS_GetPropertyStr(context, val, "signature")); | ||||
| 	result = _tf_ssb_verify_and_strip_signature_internal(context, reordered, out_id, out_id_size, out_signature, out_signature_size); | ||||
| 	result = _tf_ssb_verify_and_strip_signature_internal(context, reordered, verify_flags, out_id, out_id_size, out_signature, out_signature_size); | ||||
| 	JS_FreeValue(context, reordered); | ||||
| 	if (result) | ||||
| 	{ | ||||
| @@ -4162,7 +4174,7 @@ void tf_ssb_verify_strip_and_store_message(tf_ssb_t* ssb, JSValue value, tf_ssb_ | ||||
| 	}; | ||||
| 	char signature[crypto_sign_BYTES + 128] = { 0 }; | ||||
| 	int flags = 0; | ||||
| 	if (tf_ssb_verify_and_strip_signature(context, value, async->id, sizeof(async->id), signature, sizeof(signature), &flags)) | ||||
| 	if (tf_ssb_verify_and_strip_signature(context, value, 0, async->id, sizeof(async->id), signature, sizeof(signature), &flags)) | ||||
| 	{ | ||||
| 		async->verified = true; | ||||
| 		tf_ssb_db_store_message(ssb, context, async->id, value, signature, flags, _tf_ssb_verify_strip_and_store_callback, async); | ||||
|   | ||||
| @@ -2154,7 +2154,7 @@ static void _tf_ssb_db_set_flags(tf_ssb_t* ssb, const char* message_id, int flag | ||||
| 	tf_ssb_release_db_writer(ssb, db); | ||||
| } | ||||
|  | ||||
| bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, bool fix) | ||||
| bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, int64_t debug_sequence, bool fix) | ||||
| { | ||||
| 	JSContext* context = tf_ssb_get_context(ssb); | ||||
| 	bool verified = true; | ||||
| @@ -2177,7 +2177,8 @@ bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, bool fix) | ||||
| 				char calculated_id[k_id_base64_len]; | ||||
| 				char extracted_signature[256]; | ||||
| 				int calculated_flags = 0; | ||||
| 				if (!tf_ssb_verify_and_strip_signature(context, message, calculated_id, sizeof(calculated_id), extracted_signature, sizeof(extracted_signature), &calculated_flags)) | ||||
| 				if (!tf_ssb_verify_and_strip_signature(context, message, i == debug_sequence ? k_tf_ssb_verify_flag_debug : 0, calculated_id, sizeof(calculated_id), | ||||
| 						extracted_signature, sizeof(extracted_signature), &calculated_flags)) | ||||
| 				{ | ||||
| 					tf_printf("author=%s sequence=%" PRId64 " verify failed.\n", id, i); | ||||
| 					verified = false; | ||||
|   | ||||
| @@ -444,10 +444,11 @@ void tf_ssb_db_resolve_index_async(tf_ssb_t* ssb, const char* host, void (*callb | ||||
| ** Verify an author's feed. | ||||
| ** @param ssb The SSB instance. | ||||
| ** @param id The author'd identity. | ||||
| ** @param debug_sequence Message sequence number to debug if non-zero. | ||||
| ** @param fix Fix invalid messages when possible. | ||||
| ** @return true If the feed verified successfully. | ||||
| */ | ||||
| bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, bool fix); | ||||
| bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id, int64_t debug_sequence, bool fix); | ||||
|  | ||||
| /** | ||||
| ** Check if a user has a specific permission. | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/ssb.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/ssb.h
									
									
									
									
									
								
							| @@ -34,6 +34,14 @@ enum | ||||
| 	k_max_private_message_recipients = 8, | ||||
| }; | ||||
|  | ||||
| /** | ||||
| ** Flags affecting signature verification. | ||||
| */ | ||||
| typedef enum _tf_ssb_verify_flags_t | ||||
| { | ||||
| 	k_tf_ssb_verify_flag_debug = 1, | ||||
| } tf_ssb_verify_flags_t; | ||||
|  | ||||
| /** | ||||
| ** The type of change to a set of connections. | ||||
| */ | ||||
| @@ -446,6 +454,7 @@ bool tf_ssb_id_bin_to_str(char* str, size_t str_size, const uint8_t* bin); | ||||
| ** Verify a message's signature and remove the signature if successful. | ||||
| ** @param context A JS context. | ||||
| ** @param val The message. | ||||
| ** @param verify_flags Verification options of type tf_ssb_verify_flags_t. | ||||
| ** @param[out] out_id A buffer to receive the message's identity. | ||||
| ** @param out_id_size The size of out_id. | ||||
| ** @param[out] out_signature A buffer to receive the message's signature. | ||||
| @@ -453,7 +462,8 @@ bool tf_ssb_id_bin_to_str(char* str, size_t str_size, const uint8_t* bin); | ||||
| ** @param[out] out_flags tf_ssb_message_flags_t describing the message. | ||||
| ** @return True if the signature is valid and was successfully extracted. | ||||
| */ | ||||
| bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, int* out_flags); | ||||
| bool tf_ssb_verify_and_strip_signature( | ||||
| 	JSContext* context, JSValue val, int verify_flags, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, int* out_flags); | ||||
|  | ||||
| /** | ||||
| ** Determine the message identifier. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user