@@ -190,6 +190,7 @@ static const char *global_prefix;
190190
191191static enum sign_mode signed_tag_mode = SIGN_VERBATIM ;
192192static enum sign_mode signed_commit_mode = SIGN_VERBATIM ;
193+ static const char * signed_commit_keyid ;
193194
194195/* Memory pools */
195196static struct mem_pool fi_mem_pool = {
@@ -2836,26 +2837,15 @@ static void finalize_commit_buffer(struct strbuf *new_data,
28362837 strbuf_addbuf (new_data , msg );
28372838}
28382839
2839- static void handle_strip_if_invalid (struct strbuf * new_data ,
2840- struct signature_data * sig_sha1 ,
2841- struct signature_data * sig_sha256 ,
2842- struct strbuf * msg )
2840+ static void warn_invalid_signature (struct signature_check * check ,
2841+ const char * msg , enum sign_mode mode )
28432842{
2844- struct strbuf tmp_buf = STRBUF_INIT ;
2845- struct signature_check signature_check = { 0 };
2846- int ret ;
2847-
2848- /* Check signature in a temporary commit buffer */
2849- strbuf_addbuf (& tmp_buf , new_data );
2850- finalize_commit_buffer (& tmp_buf , sig_sha1 , sig_sha256 , msg );
2851- ret = verify_commit_buffer (tmp_buf .buf , tmp_buf .len , & signature_check );
2852-
2853- if (ret ) {
2854- const char * signer = signature_check .signer ?
2855- signature_check .signer : _ ("unknown" );
2856- const char * subject ;
2857- int subject_len = find_commit_subject (msg -> buf , & subject );
2843+ const char * signer = check -> signer ? check -> signer : _ ("unknown" );
2844+ const char * subject ;
2845+ int subject_len = find_commit_subject (msg , & subject );
28582846
2847+ switch (mode ) {
2848+ case SIGN_STRIP_IF_INVALID :
28592849 if (subject_len > 100 )
28602850 warning (_ ("stripping invalid signature for commit '%.100s...'\n"
28612851 " allegedly by %s" ), subject , signer );
@@ -2865,6 +2855,67 @@ static void handle_strip_if_invalid(struct strbuf *new_data,
28652855 else
28662856 warning (_ ("stripping invalid signature for commit\n"
28672857 " allegedly by %s" ), signer );
2858+ break ;
2859+ case SIGN_SIGN_IF_INVALID :
2860+ if (subject_len > 100 )
2861+ warning (_ ("replacing invalid signature for commit '%.100s...'\n"
2862+ " allegedly by %s" ), subject , signer );
2863+ else if (subject_len > 0 )
2864+ warning (_ ("replacing invalid signature for commit '%.*s'\n"
2865+ " allegedly by %s" ), subject_len , subject , signer );
2866+ else
2867+ warning (_ ("replacing invalid signature for commit\n"
2868+ " allegedly by %s" ), signer );
2869+ break ;
2870+ default :
2871+ BUG ("unsupported signing mode" );
2872+ }
2873+ }
2874+
2875+ static void handle_signature_if_invalid (struct strbuf * new_data ,
2876+ struct signature_data * sig_sha1 ,
2877+ struct signature_data * sig_sha256 ,
2878+ struct strbuf * msg ,
2879+ enum sign_mode mode )
2880+ {
2881+ struct strbuf tmp_buf = STRBUF_INIT ;
2882+ struct signature_check signature_check = { 0 };
2883+ int ret ;
2884+
2885+ /* Check signature in a temporary commit buffer */
2886+ strbuf_addbuf (& tmp_buf , new_data );
2887+ finalize_commit_buffer (& tmp_buf , sig_sha1 , sig_sha256 , msg );
2888+ ret = verify_commit_buffer (tmp_buf .buf , tmp_buf .len , & signature_check );
2889+
2890+ if (ret ) {
2891+ warn_invalid_signature (& signature_check , msg -> buf , mode );
2892+
2893+ if (mode == SIGN_SIGN_IF_INVALID ) {
2894+ struct strbuf signature = STRBUF_INIT ;
2895+ struct strbuf payload = STRBUF_INIT ;
2896+
2897+ /*
2898+ * NEEDSWORK: To properly support interoperability mode
2899+ * when signing commit signatures, the commit buffer
2900+ * must be provided in both the repository and
2901+ * compatibility object formats. As currently
2902+ * implemented, only the repository object format is
2903+ * considered meaning compatibility signatures cannot be
2904+ * generated. Thus, attempting to sign commit signatures
2905+ * in interoperability mode is currently unsupported.
2906+ */
2907+ if (the_repository -> compat_hash_algo )
2908+ die (_ ("signing commits in interoperability mode is unsupported" ));
2909+
2910+ strbuf_addstr (& payload , signature_check .payload );
2911+ if (sign_buffer (& payload , & signature , signed_commit_keyid ,
2912+ SIGN_BUFFER_USE_DEFAULT_KEY ))
2913+ die (_ ("failed to sign commit object" ));
2914+ add_header_signature (new_data , & signature , the_hash_algo );
2915+
2916+ strbuf_release (& signature );
2917+ strbuf_release (& payload );
2918+ }
28682919
28692920 finalize_commit_buffer (new_data , NULL , NULL , msg );
28702921 } else {
@@ -2927,6 +2978,7 @@ static void parse_new_commit(const char *arg)
29272978 /* fallthru */
29282979 case SIGN_VERBATIM :
29292980 case SIGN_STRIP_IF_INVALID :
2981+ case SIGN_SIGN_IF_INVALID :
29302982 import_one_signature (& sig_sha1 , & sig_sha256 , v );
29312983 break ;
29322984
@@ -3011,9 +3063,11 @@ static void parse_new_commit(const char *arg)
30113063 "encoding %s\n" ,
30123064 encoding );
30133065
3014- if (signed_commit_mode == SIGN_STRIP_IF_INVALID &&
3066+ if ((signed_commit_mode == SIGN_STRIP_IF_INVALID ||
3067+ signed_commit_mode == SIGN_SIGN_IF_INVALID ) &&
30153068 (sig_sha1 .hash_algo || sig_sha256 .hash_algo ))
3016- handle_strip_if_invalid (& new_data , & sig_sha1 , & sig_sha256 , & msg );
3069+ handle_signature_if_invalid (& new_data , & sig_sha1 , & sig_sha256 ,
3070+ & msg , signed_commit_mode );
30173071 else
30183072 finalize_commit_buffer (& new_data , & sig_sha1 , & sig_sha256 , & msg );
30193073
@@ -3060,6 +3114,9 @@ static void handle_tag_signature(struct strbuf *msg, const char *name)
30603114 case SIGN_STRIP_IF_INVALID :
30613115 die (_ ("'strip-if-invalid' is not a valid mode for "
30623116 "git fast-import with --signed-tags=<mode>" ));
3117+ case SIGN_SIGN_IF_INVALID :
3118+ die (_ ("'sign-if-invalid' is not a valid mode for "
3119+ "git fast-import with --signed-tags=<mode>" ));
30633120 default :
30643121 BUG ("invalid signed_tag_mode value %d from tag '%s'" ,
30653122 signed_tag_mode , name );
@@ -3649,10 +3706,10 @@ static int parse_one_option(const char *option)
36493706 } else if (skip_prefix (option , "export-pack-edges=" , & option )) {
36503707 option_export_pack_edges (option );
36513708 } else if (skip_prefix (option , "signed-commits=" , & option )) {
3652- if (parse_sign_mode (option , & signed_commit_mode ))
3709+ if (parse_sign_mode (option , & signed_commit_mode , & signed_commit_keyid ))
36533710 usagef (_ ("unknown --signed-commits mode '%s'" ), option );
36543711 } else if (skip_prefix (option , "signed-tags=" , & option )) {
3655- if (parse_sign_mode (option , & signed_tag_mode ))
3712+ if (parse_sign_mode (option , & signed_tag_mode , NULL ))
36563713 usagef (_ ("unknown --signed-tags mode '%s'" ), option );
36573714 } else if (!strcmp (option , "quiet" )) {
36583715 show_stats = 0 ;
0 commit comments