@@ -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 = {
@@ -2840,26 +2841,15 @@ static void finalize_commit_buffer(struct strbuf *new_data,
28402841 strbuf_addbuf (new_data , msg );
28412842}
28422843
2843- static void handle_strip_if_invalid (struct strbuf * new_data ,
2844- struct signature_data * sig_sha1 ,
2845- struct signature_data * sig_sha256 ,
2846- struct strbuf * msg )
2844+ static void warn_invalid_signature (struct signature_check * check ,
2845+ const char * msg , enum sign_mode mode )
28472846{
2848- struct strbuf tmp_buf = STRBUF_INIT ;
2849- struct signature_check signature_check = { 0 };
2850- int ret ;
2851-
2852- /* Check signature in a temporary commit buffer */
2853- strbuf_addbuf (& tmp_buf , new_data );
2854- finalize_commit_buffer (& tmp_buf , sig_sha1 , sig_sha256 , msg );
2855- ret = verify_commit_buffer (tmp_buf .buf , tmp_buf .len , & signature_check );
2856-
2857- if (ret ) {
2858- const char * signer = signature_check .signer ?
2859- signature_check .signer : _ ("unknown" );
2860- const char * subject ;
2861- int subject_len = find_commit_subject (msg -> buf , & subject );
2847+ const char * signer = check -> signer ? check -> signer : _ ("unknown" );
2848+ const char * subject ;
2849+ int subject_len = find_commit_subject (msg , & subject );
28622850
2851+ switch (mode ) {
2852+ case SIGN_STRIP_IF_INVALID :
28632853 if (subject_len > 100 )
28642854 warning (_ ("stripping invalid signature for commit '%.100s...'\n"
28652855 " allegedly by %s" ), subject , signer );
@@ -2869,6 +2859,67 @@ static void handle_strip_if_invalid(struct strbuf *new_data,
28692859 else
28702860 warning (_ ("stripping invalid signature for commit\n"
28712861 " allegedly by %s" ), signer );
2862+ break ;
2863+ case SIGN_SIGN_IF_INVALID :
2864+ if (subject_len > 100 )
2865+ warning (_ ("replacing invalid signature for commit '%.100s...'\n"
2866+ " allegedly by %s" ), subject , signer );
2867+ else if (subject_len > 0 )
2868+ warning (_ ("replacing invalid signature for commit '%.*s'\n"
2869+ " allegedly by %s" ), subject_len , subject , signer );
2870+ else
2871+ warning (_ ("replacing invalid signature for commit\n"
2872+ " allegedly by %s" ), signer );
2873+ break ;
2874+ default :
2875+ BUG ("unsupported signing mode" );
2876+ }
2877+ }
2878+
2879+ static void handle_signature_if_invalid (struct strbuf * new_data ,
2880+ struct signature_data * sig_sha1 ,
2881+ struct signature_data * sig_sha256 ,
2882+ struct strbuf * msg ,
2883+ enum sign_mode mode )
2884+ {
2885+ struct strbuf tmp_buf = STRBUF_INIT ;
2886+ struct signature_check signature_check = { 0 };
2887+ int ret ;
2888+
2889+ /* Check signature in a temporary commit buffer */
2890+ strbuf_addbuf (& tmp_buf , new_data );
2891+ finalize_commit_buffer (& tmp_buf , sig_sha1 , sig_sha256 , msg );
2892+ ret = verify_commit_buffer (tmp_buf .buf , tmp_buf .len , & signature_check );
2893+
2894+ if (ret ) {
2895+ warn_invalid_signature (& signature_check , msg -> buf , mode );
2896+
2897+ if (mode == SIGN_SIGN_IF_INVALID ) {
2898+ struct strbuf signature = STRBUF_INIT ;
2899+ struct strbuf payload = STRBUF_INIT ;
2900+
2901+ /*
2902+ * NEEDSWORK: To properly support interoperability mode
2903+ * when signing commit signatures, the commit buffer
2904+ * must be provided in both the repository and
2905+ * compatibility object formats. As currently
2906+ * implemented, only the repository object format is
2907+ * considered meaning compatibility signatures cannot be
2908+ * generated. Thus, attempting to sign commit signatures
2909+ * in interoperability mode is currently unsupported.
2910+ */
2911+ if (the_repository -> compat_hash_algo )
2912+ die (_ ("signing commits in interoperability mode is unsupported" ));
2913+
2914+ strbuf_addstr (& payload , signature_check .payload );
2915+ if (sign_buffer (& payload , & signature , signed_commit_keyid ,
2916+ SIGN_BUFFER_USE_DEFAULT_KEY ))
2917+ die (_ ("failed to sign commit object" ));
2918+ add_header_signature (new_data , & signature , the_hash_algo );
2919+
2920+ strbuf_release (& signature );
2921+ strbuf_release (& payload );
2922+ }
28722923
28732924 finalize_commit_buffer (new_data , NULL , NULL , msg );
28742925 } else {
@@ -2931,6 +2982,7 @@ static void parse_new_commit(const char *arg)
29312982 /* fallthru */
29322983 case SIGN_VERBATIM :
29332984 case SIGN_STRIP_IF_INVALID :
2985+ case SIGN_SIGN_IF_INVALID :
29342986 import_one_signature (& sig_sha1 , & sig_sha256 , v );
29352987 break ;
29362988
@@ -3015,9 +3067,11 @@ static void parse_new_commit(const char *arg)
30153067 "encoding %s\n" ,
30163068 encoding );
30173069
3018- if (signed_commit_mode == SIGN_STRIP_IF_INVALID &&
3070+ if ((signed_commit_mode == SIGN_STRIP_IF_INVALID ||
3071+ signed_commit_mode == SIGN_SIGN_IF_INVALID ) &&
30193072 (sig_sha1 .hash_algo || sig_sha256 .hash_algo ))
3020- handle_strip_if_invalid (& new_data , & sig_sha1 , & sig_sha256 , & msg );
3073+ handle_signature_if_invalid (& new_data , & sig_sha1 , & sig_sha256 ,
3074+ & msg , signed_commit_mode );
30213075 else
30223076 finalize_commit_buffer (& new_data , & sig_sha1 , & sig_sha256 , & msg );
30233077
@@ -3064,6 +3118,9 @@ static void handle_tag_signature(struct strbuf *msg, const char *name)
30643118 case SIGN_STRIP_IF_INVALID :
30653119 die (_ ("'strip-if-invalid' is not a valid mode for "
30663120 "git fast-import with --signed-tags=<mode>" ));
3121+ case SIGN_SIGN_IF_INVALID :
3122+ die (_ ("'sign-if-invalid' is not a valid mode for "
3123+ "git fast-import with --signed-tags=<mode>" ));
30673124 default :
30683125 BUG ("invalid signed_tag_mode value %d from tag '%s'" ,
30693126 signed_tag_mode , name );
@@ -3653,10 +3710,10 @@ static int parse_one_option(const char *option)
36533710 } else if (skip_prefix (option , "export-pack-edges=" , & option )) {
36543711 option_export_pack_edges (option );
36553712 } else if (skip_prefix (option , "signed-commits=" , & option )) {
3656- if (parse_sign_mode (option , & signed_commit_mode ))
3713+ if (parse_sign_mode (option , & signed_commit_mode , & signed_commit_keyid ))
36573714 usagef (_ ("unknown --signed-commits mode '%s'" ), option );
36583715 } else if (skip_prefix (option , "signed-tags=" , & option )) {
3659- if (parse_sign_mode (option , & signed_tag_mode ))
3716+ if (parse_sign_mode (option , & signed_tag_mode , NULL ))
36603717 usagef (_ ("unknown --signed-tags mode '%s'" ), option );
36613718 } else if (!strcmp (option , "quiet" )) {
36623719 show_stats = 0 ;
0 commit comments