git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [RFC PATCH v1 0/1] Universal cryptographic signing
@ 2021-05-08  6:18 Dave Huseby
  2021-05-08  6:18 ` [RFC PATCH v1 1/1] Modifies documentation for universal " Dave Huseby
  0 siblings, 1 reply; 4+ messages in thread
From: Dave Huseby @ 2021-05-08  6:18 UTC (permalink / raw)
  To: git

This RFC patchset is the beginning of a project generously sponsored by
Google and the Linux Foundation to modify Git to have universal
cryptographic signing capabilities. Curently Git only supports gpg and
gpgsm and the primary goal is to create the ability to use any
signing/verification tool to sign Git commits, tags, mergetags, and
pushes with a specific emphasis on supporting OpenSSH.

The goals of this project are:

- maintain full backwards compatibility without intervention. if it
  works today, it will work after these patches land without any
  modification to configs or support scripts.
- remove all tool-specific code and replace it with a protocol driver
  for using a standard protocol to talk to external signing and
  verification tools.
- normalize all of the command line switches so that they are the same
  for all tools that support signing and they are no longer tool
  specific (e.g. --sign instead of --gpgsign).
- add a new sign.* configuration structure for specifying tool specific
  configuration options (e.g. sign.openpgp.program) and deprecate all of
  the signing related config options that are no longer needed (e.g.
  user.signingKey).
- make Git completely agnostic to the details of any signing regime by
  storing signature data and options verbatim inside of signed objects
  that it later passes to the associated verification tool.
- add new tests needed to cover the new functionality while keeping all
  of the old tests passing to verify backwards compatibility.

The proposed protocol for talking to signing/verification tools is a
pkt-line based protocol inspired by the Assuan protocol used by GPG for
IPC between its component executables. The full write-up on the proposed
protocol is here:

https://github.com/TrustFrame/git-cryptography-protocol/blob/main/Git%20Cryptography%20Protocol.md

Like I said, this patchset is just the start of the project and all I
have done here is gone through all of the existing documentation and
updated it to reflect the normalized command line and config options as
well as documented the new sign.* config options and the proposed
signature format.

I am especially looking for feedback on the proposed protocol, signature
format and config structure. I have plans to follow up this project with
another project to add support for config directories (e.g.
.gitconfig.d) so that package maintainers will have an easier time of
adding sign.* config values for arbitrary signing tools.

As of right now, I have only grok'ed the handling of signed objects and
I have ignored signed pushes. I will be updating this patchset with
changes to the documentation for supporting universal signed pushes.

There's some sticky details around the transition to SHA256 that I think
I have worked out well enough that it won't get in the way. That is
documented in the hash-function-transition.txt file.

I know there is a lot here, this project cuts deep and will require tons
of test driven development to avoid killing the patient during surgery.
I look forward to the many long conversations on details ;)

Cheers!

Dave Huseby (1):
  Modifies documentation for universal cryptographic signing

 Documentation/config.txt                      |   2 +
 Documentation/config/commit.txt               |  23 +-
 Documentation/config/gpg.txt                  |  36 +--
 Documentation/config/push.txt                 |  18 +-
 Documentation/config/sign.txt                 |  72 ++++++
 Documentation/config/tag.txt                  |  27 +-
 Documentation/config/user.txt                 |  12 +-
 Documentation/git-am.txt                      |  43 +++-
 Documentation/git-cherry-pick.txt             |  43 +++-
 Documentation/git-commit-tree.txt             |  44 +++-
 Documentation/git-commit.txt                  |  43 +++-
 Documentation/git-fast-import.txt             |   2 +-
 Documentation/git-for-each-ref.txt            |   2 +-
 Documentation/git-mktag.txt                   |  32 ++-
 Documentation/git-rebase.txt                  |  44 +++-
 Documentation/git-revert.txt                  |  44 +++-
 Documentation/git-tag.txt                     | 102 +++++---
 Documentation/git-verify-commit.txt           |   8 +-
 Documentation/git-verify-tag.txt              |   8 +-
 Documentation/merge-options.txt               |  40 ++-
 Documentation/pretty-formats.txt              |   2 +-
 Documentation/pretty-options.txt              |   2 +-
 .../technical/hash-function-transition.txt    |  31 ++-
 .../technical/signature-format-v2.txt         | 232 ++++++++++++++++++
 Documentation/user-manual.txt                 |  40 +--
 25 files changed, 747 insertions(+), 205 deletions(-)
 create mode 100644 Documentation/config/sign.txt
 create mode 100644 Documentation/technical/signature-format-v2.txt

-- 
2.20.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [RFC PATCH v1 1/1] Modifies documentation for universal cryptographic signing
  2021-05-08  6:18 [RFC PATCH v1 0/1] Universal cryptographic signing Dave Huseby
@ 2021-05-08  6:18 ` Dave Huseby
  2021-05-08  7:52   ` Bagas Sanjaya
  2021-05-09  0:16   ` brian m. carlson
  0 siblings, 2 replies; 4+ messages in thread
From: Dave Huseby @ 2021-05-08  6:18 UTC (permalink / raw)
  To: git

Signed-off-by: Dave Huseby <dwh@linuxprogrammer.org>
---
 Documentation/config.txt                      |   2 +
 Documentation/config/commit.txt               |  23 +-
 Documentation/config/gpg.txt                  |  36 +--
 Documentation/config/push.txt                 |  18 +-
 Documentation/config/sign.txt                 |  72 ++++++
 Documentation/config/tag.txt                  |  27 +-
 Documentation/config/user.txt                 |  12 +-
 Documentation/git-am.txt                      |  43 +++-
 Documentation/git-cherry-pick.txt             |  43 +++-
 Documentation/git-commit-tree.txt             |  44 +++-
 Documentation/git-commit.txt                  |  43 +++-
 Documentation/git-fast-import.txt             |   2 +-
 Documentation/git-for-each-ref.txt            |   2 +-
 Documentation/git-mktag.txt                   |  32 ++-
 Documentation/git-rebase.txt                  |  44 +++-
 Documentation/git-revert.txt                  |  44 +++-
 Documentation/git-tag.txt                     | 102 +++++---
 Documentation/git-verify-commit.txt           |   8 +-
 Documentation/git-verify-tag.txt              |   8 +-
 Documentation/merge-options.txt               |  40 ++-
 Documentation/pretty-formats.txt              |   2 +-
 Documentation/pretty-options.txt              |   2 +-
 .../technical/hash-function-transition.txt    |  31 ++-
 .../technical/signature-format-v2.txt         | 232 ++++++++++++++++++
 Documentation/user-manual.txt                 |  40 +--
 25 files changed, 747 insertions(+), 205 deletions(-)
 create mode 100644 Documentation/config/sign.txt
 create mode 100644 Documentation/technical/signature-format-v2.txt

diff --git a/Documentation/config.txt b/Documentation/config.txt
index bf82766a6a..71eb46117f 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -446,6 +446,8 @@ include::config/sequencer.txt[]
 
 include::config/showbranch.txt[]
 
+include::config/sign.txt[]
+
 include::config/splitindex.txt[]
 
 include::config/ssh.txt[]
diff --git a/Documentation/config/commit.txt b/Documentation/config/commit.txt
index 2c95573930..9004a2f3cb 100644
--- a/Documentation/config/commit.txt
+++ b/Documentation/config/commit.txt
@@ -7,13 +7,24 @@ commit.cleanup::
 	have to remove the help lines that begin with `#` in the commit log
 	template yourself, if you do this).
 
-commit.gpgSign::
+commit.gpgSign (deprecated)::
+	Interpreted as an alias for 'commit.sign'. Use of this implies
+	'commit.signType = openpgp' and the config values for 
+	'sign.openpgp.*' are used if specified. If this is enabled and
+	'sign.openpgp.*' is not defined, backwards compatible defaults
+	are used that emulate the old behavior.
 
-	A boolean to specify whether all commits should be GPG signed.
-	Use of this option when doing operations such as rebase can
-	result in a large number of commits being signed. It may be
-	convenient to use an agent to avoid typing your GPG passphrase
-	several times.
+commit.sign::
+	A boolean to specify whether all commits should be cryptographically
+	signed. Use of this option when doing operations such as rebase can
+	result in a large number of commits being signed.
+
+commit.signType::
+	A string value to specify the type of signature to use whenever
+	'--sign' is used or 'commit.sign' is enabled. If this is not defined
+	the signature type defined by 'sign.default' is used. If neither
+	this nor 'sign.default' are defined backwards compatible defaults
+	for "openpgp" signatures are used.
 
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
diff --git a/Documentation/config/gpg.txt b/Documentation/config/gpg.txt
index d94025cb36..40629cb105 100644
--- a/Documentation/config/gpg.txt
+++ b/Documentation/config/gpg.txt
@@ -1,32 +1,16 @@
-gpg.program::
-	Use this custom program instead of "`gpg`" found on `$PATH` when
-	making or verifying a PGP signature. The program must support the
-	same command-line interface as GPG, namely, to verify a detached
-	signature, "`gpg --verify $signature - <$file`" is run, and the
-	program is expected to signal a good signature by exiting with
-	code 0, and to generate an ASCII-armored detached signature, the
-	standard input of "`gpg -bsau $key`" is fed with the contents to be
-	signed, and the program is expected to send the result to its
-	standard output.
+gpg.program (deprecated)::
+	Interpreted as an alias for 'sign.openpgp.program'.
 
-gpg.format::
-	Specifies which key format to use when signing with `--gpg-sign`.
-	Default is "openpgp" and another possible value is "x509".
+gpg.format (deprecated)::
+	Interpreted as an alias for 'sign.default'. 
 
-gpg.<format>.program::
-	Use this to customize the program used for the signing format you
-	chose. (see `gpg.program` and `gpg.format`) `gpg.program` can still
-	be used as a legacy synonym for `gpg.openpgp.program`. The default
-	value for `gpg.x509.program` is "gpgsm".
+gpg.<format>.program (deprecated)::
+	Interpreted as an alias for 'sign.<format>.program' for format
+	values of "openpgp" and "x509".
 
-gpg.minTrustLevel::
-	Specifies a minimum trust level for signature verification.  If
-	this option is unset, then signature verification for merge
-	operations require a key with at least `marginal` trust.  Other
-	operations that perform signature verification require a key
-	with at least `undefined` trust.  Setting this option overrides
-	the required trust-level for all operations.  Supported values,
-	in increasing order of significance:
+gpg.minTrustLevel (deprecated)::
+	Interpreted as an alias for 'sign.<format>.options.minTrustLevel' for
+	format values of "openpgp" and "x509".
 +
 * `undefined`
 * `never`
diff --git a/Documentation/config/push.txt b/Documentation/config/push.txt
index 21b256e0a4..9a63bb273a 100644
--- a/Documentation/config/push.txt
+++ b/Documentation/config/push.txt
@@ -61,15 +61,27 @@ push.followTags::
 	may override this configuration at time of push by specifying
 	`--no-follow-tags`.
 
-push.gpgSign::
+push.gpgSign (deprecated)::
+	Interpreted as an alias for 'push.sign'. Use of this implies
+	'push.signType = openpgp' and the config values for
+	'sign.openpgp.*' are used if specified. If 'sign.openpgp.*' is not
+	defined, backwards compatible defaults are used.
+
+push.sign::
 	May be set to a boolean value, or the string 'if-asked'. A true
-	value causes all pushes to be GPG signed, as if `--signed` is
+	value causes all pushes to be signed, as if `--sign` is
 	passed to linkgit:git-push[1]. The string 'if-asked' causes
 	pushes to be signed if the server supports it, as if
-	`--signed=if-asked` is passed to 'git push'. A false value may
+	`--sign=if-asked` is passed to 'git push'. A false value may
 	override a value from a lower-priority config file. An explicit
 	command-line flag always overrides this config option.
 
+push.signType::
+	Specifies the type of signature to use whenever '--sign' or
+	'push.sign' is enabled. If not defined, 'sign.default' determines
+	the type of signature otherwise backwards compatible defaults are
+	used.
+
 push.pushOption::
 	When no `--push-option=<option>` argument is given from the
 	command line, `git push` behaves as if each <value> of
diff --git a/Documentation/config/sign.txt b/Documentation/config/sign.txt
new file mode 100644
index 0000000000..a852da8803
--- /dev/null
+++ b/Documentation/config/sign.txt
@@ -0,0 +1,72 @@
+sign.default::
+	A string specifying the default signature type to use when signing
+	and the signature type is not specified with the '--sign-type'
+	command line switch. This specifies that the values from 
+	'sign.<signType>.*' be used. If unspecified, the default is "openpgp"
+	for backwards compatibility. The value can be any string but there
+	must be a corresponding 'sign.<signType>.*' config block with at
+	least 'sign.<signType>.program' defined.
+
+sign.openpgp.program::
+	Defines the program to use when signing or verifying with OpenPGP.
+	The program must be found in the `$PATH` and if not defined, the
+	default is "`gpg`".
+
+sign.openpgp.sign::
+	Defines the program, found in the `$PATH` to use when signing with
+	OpenPGP. If specified, this overrides 'sign.openpgp.program' in
+	signing operations.
+
+sign.openpgp.verify::
+	Defines the program, found in the `$PATH` to use when verifying an
+	OpenPGP signature. If specified, this overrides 'sign.openpgp.program'
+	in verification operations.
+
+sign.openpgp.options.*::
+	Any number of options that are passed verbatim to the signing tool
+	with 'OPTION' commands during a cryptographic signing event. If
+	not defined, the default, backwards compatible options are:
+	'minTrustLevel = marginal', 'armored = true', and 'detached = true'
+	for full backwards compatibility. This emulates the old
+	"`gpg -bsau`" way of creating an OpenPGP cryptographic signature.
+
+sign.x509.program::
+	Defines the program to use when signing or verifying using X.509
+	certificates. The program must be found in the `$PATH` and if not
+	defined, the default is "`gpgsm`".
+
+sign.x509.sign::
+	Defines the program, found in the `$PATH` to use when
+	cryptographically signing with X.509 certificates. If specified, this
+	overrides 'sign.x509.program' in signing operations.
+
+sign.x509.verify::
+	Defines the program, found in the `$PATH` to use when verifying an
+	X.509 cryptographic signature. If specified, this overrides
+	'sign.x509.program' in verification operations.
+
+sign.x509.options.*::
+	Any number of options that are passed verbatim to the signing tool
+	with 'OPTION' commands during a cryptographic signing event. If
+	not defined, the default options are: 'minTrustLevel = marginal',
+	'armored = true', and 'detached = true' for full backwards
+	compatibility. This emulates the old "`gpgsm -bsau`" way of creating
+	an X.509 cryptographic signature.
+
+sign.<signType>.program::
+	Defines the program, found in the `$PATH` to use when signing or
+	verifying signatures with the matching signature type.
+
+sign.<signType>.sign::
+	Defines the program, found in the `$PATH` to use when signing using
+	the specified signature type. If specified, this overrides
+	'sign.<signType>.program' in signing operations.
+
+sign.<signType>.verify::
+	Defines the program, found in the `$PATH` to use when verifying
+	signatures of type signature type. If specified, this overrides
+	'sign.<signType>.program' in verification operations.
+
+sign.<signType>.options.*::
+	Any number of options that are passed verbatim to the signing tool
+	with 'OPTION' commands during a signing event.
diff --git a/Documentation/config/tag.txt b/Documentation/config/tag.txt
index 5062a057ff..eff3286e59 100644
--- a/Documentation/config/tag.txt
+++ b/Documentation/config/tag.txt
@@ -1,17 +1,24 @@
 tag.forceSignAnnotated::
-	A boolean to specify whether annotated tags created should be GPG signed.
-	If `--annotate` is specified on the command line, it takes
-	precedence over this option.
+	A boolean to specify whether annotated tags created should be
+	cryptographically signed. If `--annotate` is specified on the
+	command line, it takes precedence over this option.
 
 tag.sort::
 	This variable controls the sort ordering of tags when displayed by
 	linkgit:git-tag[1]. Without the "--sort=<value>" option provided, the
 	value of this variable will be used as the default.
 
-tag.gpgSign::
-	A boolean to specify whether all tags should be GPG signed.
-	Use of this option when running in an automated script can
-	result in a large number of tags being signed. It is therefore
-	convenient to use an agent to avoid typing your gpg passphrase
-	several times. Note that this option doesn't affect tag signing
-	behavior enabled by "-u <keyid>" or "--local-user=<keyid>" options.
+tag.gpgSign (deprecated)::
+	Interpreted as an alias for 'tag.sign'.
+
+tag.sign::
+	A boolean to specify whether all tags should be cryptographically
+	signed. Use of this option when running in an automated script can
+	result in a large number of tags being signed. Note that this option
+	doesn't affect tag signing behavior enabled by "-u <keyid>" or
+	"--local-user=<keyid>" options.
+
+tag.sigType::
+	Specifies the type of signature to use whenever '--sign' is used or
+	'tag.sign' is enabled. If undefined, 'sign.default' determines the
+	type of signature to create.
diff --git a/Documentation/config/user.txt b/Documentation/config/user.txt
index 59aec7c3ae..a00209cd76 100644
--- a/Documentation/config/user.txt
+++ b/Documentation/config/user.txt
@@ -30,9 +30,9 @@ user.useConfigOnly::
 	making new commits in a newly cloned repository.
 	Defaults to `false`.
 
-user.signingKey::
-	If linkgit:git-tag[1] or linkgit:git-commit[1] is not selecting the
-	key you want it to automatically when creating a signed tag or
-	commit, you can override the default selection with this variable.
-	This option is passed unchanged to gpg's --local-user parameter,
-	so you may specify a key using any method that gpg supports.
+user.signingKey (deprecated)::
+	For backwards compatibility, if this is defined and if the signature
+	type is specified as 'openpgp' or 'x509' using either '--sign-type' or
+	'sign.default', then this is interpreted as an alias for
+	'sign.openpgp.options.identifier' or 'sign.x509.options.identifier'
+	respectively.
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index decd8ae122..be94598c59 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -14,7 +14,8 @@ SYNOPSIS
 	 [--ignore-date] [--ignore-space-change | --ignore-whitespace]
 	 [--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
 	 [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
-	 [--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
+	 [--[no-]scissors] [--sign] [(--sign-type <signType>)]
+	 [(--sign-option <token>[=<value])...] [--patch-format=<format>]
 	 [(<mbox> | <Maildir>)...]
 'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)])
 
@@ -146,14 +147,38 @@ default.   You can use `--no-utf8` to override this.
 	Skip the current patch.  This is only meaningful when
 	restarting an aborted patch.
 
--S[<keyid>]::
---gpg-sign[=<keyid>]::
---no-gpg-sign::
-	GPG-sign commits. The `keyid` argument is optional and
-	defaults to the committer identity; if specified, it must be
-	stuck to the option without a space. `--no-gpg-sign` is useful to
-	countermand both `commit.gpgSign` configuration variable, and
-	earlier `--gpg-sign`.
+-S::
+--sign::
+--no-sign::
+--gpg-sign[=<keyid>] (deprecated)::
+--no-gpg-sign (deprecated)::
+	Cryptographically sign commits. The `keyid` argument is deprecated
+	and the preferred way is to specify this as a configuration variable
+	as an option for the signing tool you use. For OpenPGP, you would
+	specify this using 'sign.openpgp.options.identifier = <keyid>'. If
+	you must pass the `keyid` on the command line, use
+	`--sign-option identifier=<keyid>`. For backwards compatibility, if
+	the signature type is 'openpgp' or 'x509' and the `keyid` is
+	specified, it is passed as if `--sign-option identifier=<keyid>` is
+	also specified. The `--no-sign` option is usefult to countermand both
+	'commit.sign' configuration variable and earlier `--sign` command line
+	switches.
+
+--sign-type <signType>::
+	Specifies the signature type to create when cryptographically signing
+	commits. There must be a corresponding configuration block
+	'sign.<signType>.*' with at least 'sign.<signType>.program' specified.
+	For backwards compatibility, 'openpgp' is assumed if the sign type
+	is not specified.
+
+--sign-option <token>[=<value>]::
+	Specify an option to pass to the cryptographic signing tool using the
+	OPTION command in cryptographic signing protocol. Any number of
+	options may be specified on the command line and they will override
+	any corresponding configuration variables with the same name. For
+	example, if the signature type is 'openpgp' and the configuration
+	variable 'sign.openpgp.options.identifier' is set then
+	`--sign-option identifier=<keyid>` will override it.
 
 --continue::
 -r::
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 5d750314b2..4c20e11aba 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -9,7 +9,8 @@ SYNOPSIS
 --------
 [verse]
 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
-		  [-S[<keyid>]] <commit>...
+		  [--sign] [(--sign-type <signType>)]
+		  [(--sign-option <token>[=<value>])...] <commit>...
 'git cherry-pick' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
@@ -107,14 +108,38 @@ effect to your index in a row.
 	Add a `Signed-off-by` trailer at the end of the commit message.
 	See the signoff option in linkgit:git-commit[1] for more information.
 
--S[<keyid>]::
---gpg-sign[=<keyid>]::
---no-gpg-sign::
-	GPG-sign commits. The `keyid` argument is optional and
-	defaults to the committer identity; if specified, it must be
-	stuck to the option without a space. `--no-gpg-sign` is useful to
-	countermand both `commit.gpgSign` configuration variable, and
-	earlier `--gpg-sign`.
+-S::
+--sign::
+--no-sign::
+--gpg-sign[=<keyid>] (deprecated)::
+--no-gpg-sign (deprecated)::
+	Cryptographically sign commits. The `keyid` argument is deprecated
+	and the preferred way is to specify this as a configuration variable
+	as an option for the signing tool you use. For OpenPGP, you would
+	specify this using 'sign.openpgp.options.identifier = <keyid>'. If
+	you must pass the `keyid` on the command line, use
+	`--sign-option identifier=<keyid>`. For backwards compatibility, if
+	the signature type is 'openpgp' or 'x509' and the `keyid` is
+	specified, it is passed as if `--sign-option identifier=<keyid>` is
+	also specified. The `--no-sign` option is usefult to countermand both
+	'commit.sign' configuration variable and earlier `--sign` command line
+	switches.
+
+--sign-type <signType>::
+	Specifies the signature type to create when cryptographically signing
+	commits. There must be a corresponding configuration block
+	'sign.<signType>' with at least 'sign.<signType>.program' specified.
+	For backwards compatibility, 'openpgp' is assumed if the sign type
+	is not specified.
+
+--sign-option <token>[=<value>]::
+	Specify an option to pass to the cryptographic signing tool using the
+	OPTION command in cryptographic signing protocol. Any number of options
+	may be specified on the command line and they will override
+	any corresponding configuration variables with the same name. For
+	example, if the signature type is 'openpgp' and the configuration
+	variable 'sign.openpgp.options.identifier' is set then
+	`--sign-option identifier=<keyid>` will override it.
 
 --ff::
 	If the current HEAD is the same as the parent of the
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index 2e2c581098..c7911de70a 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -10,8 +10,9 @@ SYNOPSIS
 --------
 [verse]
 'git commit-tree' <tree> [(-p <parent>)...]
-'git commit-tree' [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]
-		  [(-F <file>)...] <tree>
+'git commit-tree' [(-p <parent>)...] [--sign]
+		  [(--sign-type <signType>)] [(--sign-option <token>[=<value])...]
+		  [(-m <message>)...] [(-F <file>)...] <tree>
 
 
 DESCRIPTION
@@ -59,13 +60,38 @@ OPTIONS
 	from the standard input. This can be given more than once and the
 	content of each file becomes its own paragraph.
 
--S[<keyid>]::
---gpg-sign[=<keyid>]::
---no-gpg-sign::
-	GPG-sign commits. The `keyid` argument is optional and
-	defaults to the committer identity; if specified, it must be
-	stuck to the option without a space. `--no-gpg-sign` is useful to
-	countermand a `--gpg-sign` option given earlier on the command line.
+-S::
+--sign::
+--no-sign::
+--gpg-sign[=<keyid>] (deprecated)::
+--no-gpg-sign (deprecated)::
+	Cryptographically sign commits. The `keyid` argument is deprecated
+	and the preferred way is to specify this as a configuration variable
+	as an option for the signing tool you use. For OpenPGP, you would
+	specify this using 'sign.openpgp.options.identifier = <keyid>'. If
+	you must pass the `keyid` on the command line, use
+	`--sign-option identifier=<keyid>`. For backwards compatibility, if
+	the signature type is 'openpgp' or 'x509' and the `keyid` is
+	specified, it is passed as if `--sign-option identifier=<keyid>` is
+	also specified. The `--no-sign` option is usefult to countermand both
+	'commit.sign' configuration variable and earlier `--sign` command line
+	switches.
+
+--sign-type <signType>::
+	Specifies the signature type to create when cryptographically signing
+	commits. There must be a corresponding configuration block
+	'sign.<signType>.*' with at least 'sign.<signType>.program' specified.
+	For backwards compatibility, 'openpgp' is assumed if the sign type
+	is not specified.
+
+--sign-option <token>[=<value>]::
+	Specify an option to pass to the cryptographic signing tool using the
+	OPTION command in cryptographic signing protocol. Any number of
+	options may be specified on the command line and they will override
+	any corresponding configuration variables with the same name. For
+	example, if the signature type is 'openpgp' and the configuration
+	variable 'sign.openpgp.options.identifier' is set then
+	`--sign-option identifier=<keyid>` will override it.
 
 Commit Information
 ------------------
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 340c5fbb48..69ae92c201 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -14,7 +14,8 @@ SYNOPSIS
 	   [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
 	   [--date=<date>] [--cleanup=<mode>] [--[no-]status]
 	   [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
-	   [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]
+	   [(--trailer <token>[(=|:)<value>])...] [--sign]
+	   [(--sign-type <signType>)] [(--sign-option <token>[=<value])...]
 	   [--] [<pathspec>...]
 
 DESCRIPTION
@@ -385,14 +386,38 @@ changes to tracked files.
 	commit message template when using an editor to prepare the
 	default commit message.
 
--S[<keyid>]::
---gpg-sign[=<keyid>]::
---no-gpg-sign::
-	GPG-sign commits. The `keyid` argument is optional and
-	defaults to the committer identity; if specified, it must be
-	stuck to the option without a space. `--no-gpg-sign` is useful to
-	countermand both `commit.gpgSign` configuration variable, and
-	earlier `--gpg-sign`.
+-S::
+--sign::
+--no-sign::
+--gpg-sign[=<keyid>] (deprecated)::
+--no-gpg-sign (deprecated)::
+	Cryptographically sign commits. The `keyid` argument is deprecated
+	and the preferred way is to specify this as a configuration variable
+	as an option for the signing tool you use. For OpenPGP, you would
+	specify this using 'sign.openpgp.options.identifier = <keyid>'. If
+	you must pass the `keyid` on the command line, use
+	`--sign-option identifier=<keyid>`. For backwards compatibility, if
+	the signature type is 'openpgp' or 'x509' and the `keyid` is
+	specified, it is passed as if `--sign-option identifier=<keyid>` is
+	also specified. The `--no-sign` option is usefult to countermand both
+	'commit.sign' configuration variable and earlier `--sign` command line
+	switches.
+
+--sign-type <signType>::
+	Specifies the signature type to create when cryptographically signing
+	commits. There must be a corresponding configuration block
+	'sign.<signType>.*' with at least 'sign.<signType>.program' specified.
+	For backwards compatibility, 'openpgp' is assumed if the sign type
+	is not specified.
+
+--sign-option <token>[=<value>]::
+	Specify an option to pass to the cryptographic signing tool using the
+	OPTION command in cryptographic signing protocol. Any number of
+	options may be specified on the command line and they will override
+	any corresponding configuration variables with the same name. For
+	example, if the signature type is 'openpgp' and the configuration
+	variable 'sign.openpgp.options.identifier' is set then
+	`--sign-option identifier=<keyid>` will override it.
 
 \--::
 	Do not interpret any more arguments as options.
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 39cfa05b28..5c8e302bd8 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -854,7 +854,7 @@ not interpreted by Git.  Currently they must be encoded in UTF-8,
 as fast-import does not permit other encodings to be specified.
 
 Signing annotated tags during import from within fast-import is not
-supported.  Trying to include your own PGP/GPG signature is not
+supported.  Trying to include your own cryptographic signature is not
 recommended, as the frontend does not (easily) have access to the
 complete set of bytes which normally goes into such a signature.
 If signing is required, create lightweight tags from within fast-import with
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 2ae2478de7..fcbfd23acf 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -254,7 +254,7 @@ contents:body::
 	the "subject".
 
 contents:signature::
-	The optional GPG signature of the tag.
+	The optional cryptographic signature of the tag.
 
 contents:lines=N::
 	The first `N` lines of the message.
diff --git a/Documentation/git-mktag.txt b/Documentation/git-mktag.txt
index 466a697519..19b8998195 100644
--- a/Documentation/git-mktag.txt
+++ b/Documentation/git-mktag.txt
@@ -48,18 +48,34 @@ OPTIONS
 Tag Format
 ----------
 A tag signature file, to be fed to this command's standard input,
-has a very simple fixed format: four lines of
+must have at least these four lines:
 
-  object <hash>
-  type <typename>
-  tag <tagname>
-  tagger <tagger>
+object <hash>
+type <typename>
+tag <tagname>
+tagger <tagger>
 
 followed by some 'optional' free-form message (some tags created
 by older Git may not have `tagger` line).  The message, when it
-exists, is separated by a blank line from the header.  The
-message part may contain a signature that Git itself doesn't
-care about, but that can be verified with gpg.
+exists, is separated by a blank line from the header.
+
+A cryptographically signed tag may be created by including a
+signature formatted using the version 2 format:
+
+object <hash>
+type <typename>
+tag <tagname>
+tagger <tagger>
+signtype openpgp
+sign -----BEGIN PGP SIGNATURE-----%0a
+ %0a
+ iHUEABYKAB0WIQTXto4BPKlfA2YYS5Pn3hDaTgk8fAUCX5C+ugAKCRDn3hDaTgk8%0a
+ fOk8AQCRGkdNGMXhJ95e5QIHk44rvfNsyibxY6ZvTXdLQJvt/gEAlFCeEM3SfaDL%0a
+ 8RQR368L0+caDlaZW51VZVP2UBXP6w0=%0a
+ =1Fby%0a
+ -----END PGP SIGNATURE-----%0a
+
+followed by an optional free-form message.
 
 GIT
 ---
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 55af6fd24e..c9654dff6e 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -9,8 +9,10 @@ SYNOPSIS
 --------
 [verse]
 'git rebase' [-i | --interactive] [<options>] [--exec <cmd>]
-	[--onto <newbase> | --keep-base] [<upstream> [<branch>]]
+	 [--sign] [(--sign-type <signType>)] [(--sign-option <token>[=<value])...]
+	 [--onto <newbase> | --keep-base] [<upstream> [<branch>]]
 'git rebase' [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
+	 [--sign] [(--sign-type <signType>)] [(--sign-option <token>[=<value])...]
 	--root [<branch>]
 'git rebase' (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch)
 
@@ -379,14 +381,38 @@ See also INCOMPATIBLE OPTIONS below.
 	Allow the rerere mechanism to update the index with the
 	result of auto-conflict resolution if possible.
 
--S[<keyid>]::
---gpg-sign[=<keyid>]::
---no-gpg-sign::
-	GPG-sign commits. The `keyid` argument is optional and
-	defaults to the committer identity; if specified, it must be
-	stuck to the option without a space. `--no-gpg-sign` is useful to
-	countermand both `commit.gpgSign` configuration variable, and
-	earlier `--gpg-sign`.
+-S::
+--sign::
+--no-sign::
+--gpg-sign[=<keyid>] (deprecated)::
+--no-gpg-sign (deprecated)::
+	Cryptographically sign commits. The `keyid` argument is deprecated
+	and the preferred way is to specify this as a configuration variable
+	as an option for the signing tool you use. For OpenPGP, you would
+	specify this using 'sign.openpgp.options.identifier = <keyid>'. If
+	you must pass the `keyid` on the command line, use
+	`--sign-option identifier=<keyid>`. For backwards compatibility, if
+	the signature type is 'openpgp' or 'x509' and the `keyid` is
+	specified, it is passed as if `--sign-option identifier=<keyid>` is
+	also specified. The `--no-sign` option is usefult to countermand both
+	'commit.sign' configuration variable and earlier `--sign` command line
+	switches.
+
+--sign-type <signType>::
+	Specifies the signature type to create when cryptographically signing
+	commits. There must be a corresponding configuration block
+	'sign.<signType>.*' with at least 'sign.<signType>.program' specified.
+	For backwards compatibility, 'openpgp' is assumed if the sign type
+	is not specified.
+
+--sign-option <token>[=<value>]::
+	Specify an option to pass to the cryptographic signing tool using the
+	OPTION command in cryptographic signing protocol. Any number of
+	options may be specified on the command line and they will override
+	any corresponding configuration variables with the same name. For
+	example, if the signature type is 'openpgp' and the configuration
+	variable 'sign.openpgp.options.identifier' is set then
+	`--sign-option identifier=<keyid>` will override it.
 
 -q::
 --quiet::
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index bb92a4a451..5ea0ee9bd3 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -8,7 +8,9 @@ git-revert - Revert some existing commits
 SYNOPSIS
 --------
 [verse]
-'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
+'git revert' [--[no-]edit] [-n] [-m parent-number] [-s]
+	[--sign] [(--sign-type <signType>)] [(--sign-option <token>[=<value])...]
+	<commit>...
 'git revert' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
@@ -88,14 +90,38 @@ more details.
 This is useful when reverting more than one commits'
 effect to your index in a row.
 
--S[<keyid>]::
---gpg-sign[=<keyid>]::
---no-gpg-sign::
-	GPG-sign commits. The `keyid` argument is optional and
-	defaults to the committer identity; if specified, it must be
-	stuck to the option without a space. `--no-gpg-sign` is useful to
-	countermand both `commit.gpgSign` configuration variable, and
-	earlier `--gpg-sign`.
+-S::
+--sign::
+--no-sign::
+--gpg-sign[=<keyid>] (deprecated)::
+--no-gpg-sign (deprecated)::
+	Cryptographically sign commits. The `keyid` argument is deprecated
+	and the preferred way is to specify this as a configuration variable
+	as an option for the signing tool you use. For OpenPGP, you would
+	specify this using 'sign.openpgp.options.identifier = <keyid>'. If
+	you must pass the `keyid` on the command line, use
+	`--sign-option identifier=<keyid>`. For backwards compatibility, if
+	the signature type is 'openpgp' or 'x509' and the `keyid` is
+	specified, it is passed as if `--sign-option identifier=<keyid>` is
+	also specified. The `--no-sign` option is usefult to countermand both
+	'commit.sign' configuration variable and earlier `--sign` command line
+	switches.
+
+--sign-type <signType>::
+	Specifies the signature type to create when cryptographically signing
+	commits. There must be a corresponding configuration block
+	'sign.<signType>.*' with at least 'sign.<signType>.program' specified.
+	For backwards compatibility, 'openpgp' is assumed if the sign type
+	is not specified.
+
+--sign-option <token>[=<value>]::
+	Specify an option to pass to the cryptographic signing tool using the
+	OPTION command in cryptographic signing protocol. Any number of
+	options may be specified on the command line and they will override
+	any corresponding configuration variables with the same name. For
+	example, if the signature type is 'openpgp' and the configuration
+	variable 'sign.openpgp.options.identifier' is set then
+	`--sign-option identifier=<keyid>` will override it.
 
 -s::
 --signoff::
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 31a97a1b6c..764939ec93 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -3,13 +3,14 @@ git-tag(1)
 
 NAME
 ----
-git-tag - Create, list, delete or verify a tag object signed with GPG
+git-tag - Create, list, delete or verify a tag object
 
 
 SYNOPSIS
 --------
 [verse]
-'git tag' [-a | -s | -u <keyid>] [-f] [-m <msg> | -F <file>] [-e]
+'git tag' [-a] [--sign] [(--sign-type <signType>)] 
+  [(--sign-option <token>[=<value])...][-f] [-m <msg> | -F <file>] [-e]
 	<tagname> [<commit> | <object>]
 'git tag' -d <tagname>...
 'git tag' [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
@@ -26,26 +27,23 @@ to delete, list or verify tags.
 
 Unless `-f` is given, the named tag must not yet exist.
 
-If one of `-a`, `-s`, or `-u <keyid>` is passed, the command
-creates a 'tag' object, and requires a tag message.  Unless
-`-m <msg>` or `-F <file>` is given, an editor is started for the user to type
-in the tag message.
+If one of `-a`, is passed, the command creates a 'tag' object, and
+requires a tag message.  Unless `-m <msg>` or `-F <file>` is given,
+an editor is started for the user to type in the tag message.
 
-If `-m <msg>` or `-F <file>` is given and `-a`, `-s`, and `-u <keyid>`
-are absent, `-a` is implied.
+If `-m <msg>` or `-F <file>` is given and `-a` is absent, `-a` is
+implied.
 
 Otherwise, a tag reference that points directly at the given object
 (i.e., a lightweight tag) is created.
 
-A GnuPG signed tag object will be created when `-s` or `-u
-<keyid>` is used.  When `-u <keyid>` is not used, the
-committer identity for the current user is used to find the
-GnuPG key for signing. 	The configuration variable `gpg.program`
-is used to specify custom GnuPG binary.
+A cryptographically signed object is created when `--sign` is used.
+The type of signature to create may be specified using `--sign-type`
+and options specified using `--sign-option`.
 
-Tag objects (created with `-a`, `-s`, or `-u`) are called "annotated"
+Tag objects (created with `-a` or `--sign`) are called "annotated"
 tags; they contain a creation date, the tagger name and e-mail, a
-tagging message, and an optional GnuPG signature. Whereas a
+tagging message, and an optional cryptographic signature. Whereas a
 "lightweight" tag is simply a name for an object (usually a commit
 object).
 
@@ -61,20 +59,41 @@ OPTIONS
 --annotate::
 	Make an unsigned, annotated tag object
 
--s::
+-S::
 --sign::
-	Make a GPG-signed tag, using the default e-mail address's key.
-	The default behavior of tag GPG-signing is controlled by `tag.gpgSign`
-	configuration variable if it exists, or disabled otherwise.
-	See linkgit:git-config[1].
-
 --no-sign::
-	Override `tag.gpgSign` configuration variable that is
-	set to force each and every tag to be signed.
-
--u <keyid>::
---local-user=<keyid>::
-	Make a GPG-signed tag, using the given key.
+-s (deprecated)::
+	Cryptographically sign the tag. The `--no-sign` option is usefult to
+	countermand both 'commit.sign' configuration variable and earlier 
+	`--sign` command line switches.
+
+-u <keyid> (deprecated)::
+--local-user=<keyid> (deprecated)::
+	Both of these options are deprecated and should no longer be used.
+	The preferred way is to specify this as a configuration variable as
+	an option for the signing tool you use. For OpenPGP, you would
+	specify this using 'sign.openpgp.options.identifier = <keyid>'. If
+	you must pass the `keyid` on the command line, use
+	`--sign-option identifier=<keyid>`. For backwards compatibility, if
+	the signature type is 'openpgp' or 'x509' and the `keyid` is
+	specified, it is passed as if `--sign-option identifier=<keyid>` is
+	also specified. 
+
+--sign-type <signType>::
+	Specifies the signature type to create when cryptographically signing
+	commits. There must be a corresponding configuration block
+	'sign.<signType>.*' with at least 'sign.<signType>.program' specified.
+	For backwards compatibility, 'openpgp' is assumed if the sign type
+	is not specified.
+
+--sign-option <token>[=<value>]::
+	Specify an option to pass to the cryptographic signing tool using the
+	OPTION command in cryptographic signing protocol. Any number of
+	options may be specified on the command line and they will override
+	any corresponding configuration variables with the same name. For
+	example, if the signature type is 'openpgp' and the configuration
+	variable 'sign.openpgp.options.identifier' is set then
+	`--sign-option identifier=<keyid>` will override it.
 
 -f::
 --force::
@@ -86,7 +105,7 @@ OPTIONS
 
 -v::
 --verify::
-	Verify the GPG signature of the given tag names.
+	Verify the cryptographic signature of the given tag names.
 
 -n<num>::
 	<num> specifies how many lines from the annotation, if any,
@@ -213,15 +232,24 @@ This option is only applicable when listing tags without annotation lines.
 
 CONFIGURATION
 -------------
-By default, 'git tag' in sign-with-default mode (-s) will use your
-committer identity (of the form `Your Name <your@email.address>`) to
-find a key.  If you want to use a different default key, you can specify
-it in the repository configuration as follows:
-
--------------------------------------
-[user]
-    signingKey = <gpg-keyid>
--------------------------------------
+By default, 'git tag' in sign-with-default mode (-S) determines the
+type of signature from the `sign.default` config option and/or the
+`--sign-type` command line option. The identifier for the signature
+is then determined by the `sign.<signType>.options.identifier` config
+option and/or the `--sign-option identifier=<keyid>` command line
+option.
+
+For backwards compatibility, if you are still using the deprecated
+`user.signingKey` config option and enable tag signing, the behavior
+is as if you also specified the following command line options:
+
+	--sign-type openpgp
+	--sign-option armored=true 
+	--sign-option detached=true
+	--sign-option identifier=<keyid>
+
+which emulates the original signing behavior of running
+`gpg -bsau <keyid>` to create the signature.
 
 `pager.tag` is only respected when listing tags, i.e., when `-l` is
 used or implied. The default is to use a pager.
diff --git a/Documentation/git-verify-commit.txt b/Documentation/git-verify-commit.txt
index 92097f6673..4b2e8ea909 100644
--- a/Documentation/git-verify-commit.txt
+++ b/Documentation/git-verify-commit.txt
@@ -3,7 +3,7 @@ git-verify-commit(1)
 
 NAME
 ----
-git-verify-commit - Check the GPG signature of commits
+git-verify-commit - Check the cryptographic signature of commits
 
 SYNOPSIS
 --------
@@ -12,13 +12,13 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Validates the GPG signature created by 'git commit -S'.
+Validates the cryptographic signature created by 'git commit -S'.
 
 OPTIONS
 -------
 --raw::
-	Print the raw gpg status output to standard error instead of the normal
-	human-readable output.
+	Print the raw signature verification status output to standard error 
+	instead of the normal human-readable output.
 
 -v::
 --verbose::
diff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.txt
index 0b8075dad9..939cf8dc3a 100644
--- a/Documentation/git-verify-tag.txt
+++ b/Documentation/git-verify-tag.txt
@@ -3,7 +3,7 @@ git-verify-tag(1)
 
 NAME
 ----
-git-verify-tag - Check the GPG signature of tags
+git-verify-tag - Check the cryptographic signature of tags
 
 SYNOPSIS
 --------
@@ -12,13 +12,13 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Validates the gpg signature created by 'git tag'.
+Validates the cryptographic signature created by 'git tag'.
 
 OPTIONS
 -------
 --raw::
-	Print the raw gpg status output to standard error instead of the normal
-	human-readable output.
+	Print the raw signature verification status output to standard error
+	instead of the normal human-readable output.
 
 -v::
 --verbose::
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index eb0aabd396..ba521f90d3 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -59,14 +59,38 @@ could instead be resolved as a fast-forward.
 With `--ff-only`, resolve the merge as a fast-forward when possible.
 When not possible, refuse to merge and exit with a non-zero status.
 
--S[<keyid>]::
---gpg-sign[=<keyid>]::
---no-gpg-sign::
-	GPG-sign the resulting merge commit. The `keyid` argument is
-	optional and defaults to the committer identity; if specified,
-	it must be stuck to the option without a space. `--no-gpg-sign`
-	is useful to countermand both `commit.gpgSign` configuration variable,
-	and earlier `--gpg-sign`.
+-S::
+--sign::
+--no-sign::
+--gpg-sign[=<keyid>] (deprecated)::
+--no-gpg-sign (deprecated)::
+	Cryptographically sign commits. The `keyid` argument is deprecated
+	and the preferred way is to specify this as a configuration variable
+	as an option for the signing tool you use. For OpenPGP, you would
+	specify this using 'sign.openpgp.options.identifier = <keyid>'. If
+	you must pass the `keyid` on the command line, use
+	`--sign-option identifier=<keyid>`. For backwards compatibility, if
+	the signature type is 'openpgp' or 'x509' and the `keyid` is
+	specified, it is passed as if `--sign-option identifier=<keyid>` is
+	also specified. The `--no-sign` option is usefult to countermand both
+	'commit.sign' configuration variable and earlier `--sign` command line
+	switches.
+
+--sign-type <signType>::
+	Specifies the signature type to create when cryptographically signing
+	commits. There must be a corresponding configuration block
+	'sign.<signType>.*' with at least 'sign.<signType>.program' specified.
+	For backwards compatibility, 'openpgp' is assumed if the sign type
+	is not specified.
+
+--sign-option <token>[=<value>]::
+	Specify an option to pass to the cryptographic signing tool using the
+	OPTION command in cryptographic signing protocol. Any number of
+	options may be specified on the command line and they will override
+	any corresponding configuration variables with the same name. For
+	example, if the signature type is 'openpgp' and the configuration
+	variable 'sign.openpgp.options.identifier' is set then
+	`--sign-option identifier=<keyid>` will override it.
 
 --log[=<n>]::
 --no-log::
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index cd697f508c..229ddabbd7 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -235,7 +235,7 @@ The placeholders are:
 ifndef::git-rev-list[]
 '%N':: commit notes
 endif::git-rev-list[]
-'%GG':: raw verification message from GPG for a signed commit
+'%GG':: raw verification message for a cryptographically signed commit
 '%G?':: show "G" for a good (valid) signature,
 	"B" for a bad signature,
 	"U" for a good signature with unknown validity,
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 27ddaf84a1..45bd13bb25 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -93,4 +93,4 @@ endif::git-rev-list[]
 
 --show-signature::
 	Check the validity of a signed commit object by passing the signature
-	to `gpg --verify` and show the output.
+	to associated verification tool and show the output.
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.txt
index 7c1630bf83..d9bd4082c3 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.txt
@@ -409,17 +409,16 @@ send-pack.
 
 Signed Commits
 ~~~~~~~~~~~~~~
-We add a new field "gpgsig-sha256" to the commit object format to allow
-signing commits without relying on SHA-1. It is similar to the
-existing "gpgsig" field. Its signed payload is the SHA-256 content of the
-commit object with any "gpgsig" and "gpgsig-sha256" fields removed.
+We use the new signature format whenever signing commits without relying
+on SHA-1. The new format adds a 'signtype' field, zero or more 'signoption'
+fields, and one 'sign' field to commit objects. This allows for the 'gpgsig'
+field to coexist if needed.
 
 This means commits can be signed
 
 1. using SHA-1 only, as in existing signed commit objects
-2. using both SHA-1 and SHA-256, by using both gpgsig-sha256 and gpgsig
-   fields.
-3. using only SHA-256, by only using the gpgsig-sha256 field.
+2. using both SHA-1 and SHA-256, by using both gpgsig and the V2 format.
+3. using only SHA-256, by only using the V2 format.
 
 Old versions of "git verify-commit" can verify the gpgsig signature in
 cases (1) and (2) without modifications and view case (3) as an
@@ -427,17 +426,16 @@ ordinary unsigned commit.
 
 Signed Tags
 ~~~~~~~~~~~
-We add a new field "gpgsig-sha256" to the tag object format to allow
-signing tags without relying on SHA-1. Its signed payload is the
-SHA-256 content of the tag with its gpgsig-sha256 field and "-----BEGIN PGP
-SIGNATURE-----" delimited in-body signature removed.
+We use the new signature format whenever signing tags without relying
+on SHA-1. The new format adds a 'signtype' field, zero or more 'signoption'
+fields, and one 'sign' field to tag objects. This allows for the in-body
+SHA-1 signature to coexist if needed.
 
 This means tags can be signed
 
 1. using SHA-1 only, as in existing signed tag objects
-2. using both SHA-1 and SHA-256, by using gpgsig-sha256 and an in-body
-   signature.
-3. using only SHA-256, by only using the gpgsig-sha256 field.
+2. using both SHA-1 and SHA-256, by using both gpgsig and the V2 format.
+3. using only SHA-256, by only using the V2 format.
 
 Mergetag embedding
 ~~~~~~~~~~~~~~~~~~
@@ -631,8 +629,9 @@ Transition plan
 Some initial steps can be implemented independently of one another:
 
 - adding a hash function API (vtable)
-- teaching fsck to tolerate the gpgsig-sha256 field
-- excluding gpgsig-* from the fields copied by "git commit --amend"
+- teaching fsck to tolerate the 'signtype', 'signoption' and 'sign' tags
+- excluding 'signtype', 'signoption' and 'sign' from the fields copied
+  by "git commit --amend"
 - annotating tests that depend on SHA-1 values with a SHA1 test
   prerequisite
 - using "struct object_id", GIT_MAX_RAWSZ, and GIT_MAX_HEXSZ
diff --git a/Documentation/technical/signature-format-v2.txt b/Documentation/technical/signature-format-v2.txt
new file mode 100644
index 0000000000..8628402e29
--- /dev/null
+++ b/Documentation/technical/signature-format-v2.txt
@@ -0,0 +1,232 @@
+Git Signature Format, Version 2
+===============================
+
+Overview
+--------
+
+Git supports cryptographic signatures on objecs (e.g. tags, commits, mergetags)
+and transactions (e.g. pushes). The first version of these signatures were
+always created using gpg or gpgsm and resulted in OpenPGP signatures with known
+formats that made parsing signatures for verification simple using string
+matching. Version 2 of signature format is designed to work hand-in-hand with
+the new cryptographic signing/verification protocol and supports any possible
+signature format while still being easily parseable for verification purposes.
+
+Version 1 Format
+----------------
+
+The first verion of the protocol is documented in the signature-format.txt
+file. The relevant details from that document define the fields used to
+identify signatures in the meta data of objects and transations.
+
+Tags
+~~~~
+
+In tags, signatures are stored "in-body" immediately following the tag body.
+To parse a signature from a tag, Git string matches for `-----BEGIN PGP
+SIGNATURE-----` and `-----END PGP SIGNATURE-----` that mark the begining and
+ending of a signature. The only difference between gpg and gpgsm signatures is
+that gpgsm signatures use the strings `-----BEGIN SIGNED MESSAGE-----` and
+`-----END SIGNED MESSAGE-----` instead.
+
+The transition from SHA1 to SHA256 has complicated this somewhat by adding a
+new "gpgsig-sha256" field that stores the signature whenever the SHA256 digest
+algorithm is used. It is possible to have both the "in-body" signature created
+when SHA-1 digest is used as well as the signature stored as the value for the
+"gpgsig-sha256" field when SHA256 digest is used.
+
+Either way, the content that gets sent to the signing tool is the full object
+data, fields and body, without including the "gpgsig-sha256" field or any
+in-body signature data.
+
+Commits
+~~~~~~~
+
+In commits, signatures are stored in the field named "gpgsig" when SHA-1 digest
+is used and "gpgsig-sha256" when SHA256 digest is used. Parsing signatures in
+commits is also done with string matching of the BEGIN/END strings marking
+OpenPGP signatures even though they are stored as fields.
+
+Mergetags
+~~~~~~~~~
+
+In mergtags, the whole signed tag object is stored in the field named
+"mergetag" and the output of verifying the signature is appended to the body of
+the mergetag as comment lines starting with '#'.
+
+Version 2 Format
+----------------
+
+The goals of the version 2 format are as follows:
+
+- Backwards Compatible with version 1 without any intervention.
+- Eliminate signature-format-specific string matching for detecting/parsing
+  version 2 signatures.
+- Use fields for storing signatures in all objects and transactions.
+- Have a field that identifies the signature format.
+- Have fields that store options required by the verification tool.
+- Store signature data verbatim as created with the signing tool with escaped
+  newlines and carriage returns.
+
+Fields
+~~~~~~
+
+The version 2 format uses three new fields listed below:
+
+- signtype <signature format name>
+- signoption <token> [= <value>]
+- sign <multiline signature data>
+
+A complete signature must include exactly one `signtype` field, zero or more
+`signoption` fields and one `sign` field.
+
+The `signtype` field has a string value that identifies the type of signature
+that is stored in the object. This string is case-insensitive and is used to
+identify which configuration settings are to used when verifying the signature.
+The corresponding configuration settings are in the config file as:
+'sign.<signType>.options.*'. The 'sign' field stores the text-encoded signature
+from the signing tool with any newlines and carriage returns escaped as '%0a'
+and '%0d' respectively. Whitespace is significant in digital signatures and
+the protocol for sending/receiving data to/from signing and verification tools
+requires that newlines and carriage returns are escaped. By storing the escaped
+version in the 'sign' field, we avoid extra processing and error-prone
+escaping.
+
+The introduction of the 'signoption' field is necessary for Git to remain
+agnostic to the tools used for signing and verification of cryptographic
+signatures. Some signign tools do not produce cryptographic signatures that
+include all of the data needed to verify the signature. A good example of this
+is the minisign tool (https://jedisct1.github.io/minisign/) which requires the
+public key to be supplied to the verification operation. In that case, the
+signing operation would return to Git a 'signoption' field along with the
+'signtype' and 'sign' fields to be stored in the Git object. When Git verifies
+the signature, it will parse the 'signoption' fields and send them to the
+verification tool as OPTION commands. In this case it will send the public key
+along with the signature for verification. This design allows for arbitrary
+options to be stored in the Git object by the signing tool that will get passed
+to the verification tool later without Git knowing or understanding any details
+of a particular signing tool.
+
+The order in which OPTION commands are sent to the signing and verification
+tools is significant. OPTION commands that come later override OPTION commands
+that came earlier and had the same token name. Git always sends OPTION commands
+from the command line after the options from the config. In verification
+operations, Git sends the options from the signed object first, before the
+config and command line options. This ensures local control over option values.
+An example would be if the sign.openpgp.options.minTrustLevel config option is
+set to "marginal" and the command line `--sign-option minTrustLevel = full` is
+issued. Git would first send an OPTION command setting 
+`minTrustLevel = marginal` from the config and then override that by later
+sending an OPTION command setting `minTrustLevel = full` from the command line.
+
+The `sign` field is very similar to the old `gpgsig` field in commits. The data
+is can be multi-line with subsequent lines starting with spaces to mark them as
+additional data. The only difference is that the `sign` field stores signatures
+with newlines and carriage returns escaped because whitespace is significate in
+cryptographic signatures. Again, the idea is to keep Git completely agnostic to
+the details of any cryptographic signing/verification tool so the signature
+data must be escaped and stored verbatim in the object. This allows simple and
+exact transmission of the signature data to the verification tool in the
+future.
+
+Examples
+~~~~~~~~
+
+Below are the examples taken from the Version 1 signature-format.txt
+documentation and translated into objects that use the Version 2 format as an
+example.
+
+Signed Tag:
+
+----
+object 04b871796dc0420f8e7561a895b52484b701d51a
+type commit
+tag signedtag
+tagger C O Mitter <committer@example.com> 1465981006 +0000
+signtype openpgp
+sign -----BEGIN PGP SIGNATURE-----%0a
+ Version: GnuPG v1%0a
+ %0a
+ iQEcBAABAgAGBQJXYRhOAAoJEGEJLoW3InGJklkIAIcnhL7RwEb/+QeX9enkXhxn%0a
+ rxfdqrvWd1K80sl2TOt8Bg/NYwrUBw/RWJ+sg/hhHp4WtvE1HDGHlkEz3y11Lkuh%0a
+ 8tSxS3qKTxXUGozyPGuE90sJfExhZlW4knIQ1wt/yWqM+33E9pN4hzPqLwyrdods%0a
+ q8FWEqPPUbSJXoMbRPw04S5jrLtZSsUWbRYjmJCHzlhSfFWW4eFd37uquIaLUBS0%0a
+ rkC3Jrx7420jkIpgFcTI2s60uhSQLzgcCwdA2ukSYIRnjg/zDkj8+3h/GaROJ72x%0a
+ lZyI6HWixKJkWw8lE9aAOD9TmTW9sFJwcVAzmAuFX2kUreDUKMZduGcoRYGpD7E=%0a
+ =jpXa%0a
+ -----END PGP SIGNATURE-----%0a
+
+signed tag
+
+signed tag message body
+----
+
+
+Signed Commit:
+
+----
+tree eebfed94e75e7760540d1485c740902590a00332
+parent 04b871796dc0420f8e7561a895b52484b701d51a
+author A U Thor <author@example.com> 1465981137 +0000
+committer C O Mitter <committer@example.com> 1465981137 +0000
+signtype openpgp
+sign -----BEGIN PGP SIGNATURE-----%0a
+ Version: GnuPG v1%0a
+ %0a
+ iQEcBAABAgAGBQJXYRjRAAoJEGEJLoW3InGJ3IwIAIY4SA6GxY3BjL60YyvsJPh/%0a
+ HRCJwH+w7wt3Yc/9/bW2F+gF72kdHOOs2jfv+OZhq0q4OAN6fvVSczISY/82LpS7%0a
+ DVdMQj2/YcHDT4xrDNBnXnviDO9G7am/9OE77kEbXrp7QPxvhjkicHNwy2rEflAA%0a
+ zn075rtEERDHr8nRYiDh8eVrefSO7D+bdQ7gv+7GsYMsd2auJWi1dHOSfTr9HIF4%0a
+ HJhWXT9d2f8W+diRYXGh4X0wYiGg6na/soXc+vdtDYBzIxanRqjg8jCAeo1eOTk1%0a
+ EdTwhcTZlI0x5pvJ3H0+4hA2jtldVtmPM4OTB0cTrEWBad7XV6YgiyuII73Ve3I=%0a
+ =jKHM%0a
+ -----END PGP SIGNATURE-----%0a
+
+signed commit
+
+signed commit message body
+----
+
+
+Signed Mergetag:
+
+----
+tree c7b1cff039a93f3600a1d18b82d26688668c7dea
+parent c33429be94b5f2d3ee9b0adad223f877f174b05d
+parent 04b871796dc0420f8e7561a895b52484b701d51a
+author A U Thor <author@example.com> 1465982009 +0000
+committer C O Mitter <committer@example.com> 1465982009 +0000
+mergetag object 04b871796dc0420f8e7561a895b52484b701d51a
+ type commit
+ tag signedtag
+ tagger C O Mitter <committer@example.com> 1465981006 +0000
+ signtype openpgp
+ sign  -----BEGIN PGP SIGNATURE-----%0a
+ Version: GnuPG v1%0a
+ %0a
+ iQEcBAABAgAGBQJXYRhOAAoJEGEJLoW3InGJklkIAIcnhL7RwEb/+QeX9enkXhxn%0a
+ rxfdqrvWd1K80sl2TOt8Bg/NYwrUBw/RWJ+sg/hhHp4WtvE1HDGHlkEz3y11Lkuh%0a
+ 8tSxS3qKTxXUGozyPGuE90sJfExhZlW4knIQ1wt/yWqM+33E9pN4hzPqLwyrdods%0a
+ q8FWEqPPUbSJXoMbRPw04S5jrLtZSsUWbRYjmJCHzlhSfFWW4eFd37uquIaLUBS0%0a
+ rkC3Jrx7420jkIpgFcTI2s60uhSQLzgcCwdA2ukSYIRnjg/zDkj8+3h/GaROJ72x%0a
+ lZyI6HWixKJkWw8lE9aAOD9TmTW9sFJwcVAzmAuFX2kUreDUKMZduGcoRYGpD7E=%0a
+ =jpXa%0a
+ -----END PGP SIGNATURE-----%0a
+
+ signed tag
+
+ signed tag message body
+
+Merge tag 'signedtag' into downstream
+
+signed tag
+
+signed tag message body
+
+# Signature made Wed Jun 15 08:56:46 2016 UTC using RSA key ID B7227189
+# Good signature from "Eris Discordia <discord@example.net>"
+# WARNING: This key is not certified with a trusted signature!
+#          There is no indication that the signature belongs to the owner.
+# Primary key fingerprint: D4BE 2231 1AD3 131E 5EDA  29A4 6109 2E85 B722 7189
+----
+
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index f9e54b8674..a5922d0364 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -2930,7 +2930,7 @@ There are four different types of objects: "blob", "tree", "commit", and
 - A <<def_tag_object,"tag" object>> symbolically identifies and can be
   used to sign other objects. It contains the object name and type of
   another object, a symbolic name (of course!) and, optionally, a
-  signature.
+  cryptographic signature.
 
 The object types in some more detail:
 
@@ -3071,15 +3071,15 @@ parents of that commit, and all of those contents of the trees referred
 to by those commits.
 
 So to introduce some real trust in the system, the only thing you need
-to do is to digitally sign just 'one' special note, which includes the
-name of a top-level commit.  Your digital signature shows others
-that you trust that commit, and the immutability of the history of
-commits tells others that they can trust the whole history.
+to do is to cryptographically sign just 'one' special note, which
+includes the name of a top-level commit. Your cryptographic signature
+shows others that you trust that commit, and the immutability of the
+history of commits tells others that they can trust the whole history.
 
 In other words, you can easily validate a whole archive by just
 sending out a single email that tells the people the name (SHA-1 hash)
-of the top commit, and digitally sign that email using something
-like GPG/PGP.
+of the top commit, and cryptographically sign that email using
+something like GPG/PGP.
 
 To assist in this, Git also provides the tag object...
 
@@ -3087,8 +3087,8 @@ To assist in this, Git also provides the tag object...
 ==== Tag Object
 
 A tag object contains an object, object type, tag name, the name of the
-person ("tagger") who created the tag, and a message, which may contain
-a signature, as can be seen using linkgit:git-cat-file[1]:
+person ("tagger") who created the tag, an optional cryptographic
+signature, and a message as can be seen using linkgit:git-cat-file[1]:
 
 ------------------------------------------------
 $ git cat-file tag v1.5.0
@@ -3096,15 +3096,17 @@ object 437b1b20df4b356c9342dac8d38849f24ef44f27
 type commit
 tag v1.5.0
 tagger Junio C Hamano <junkio@cox.net> 1171411200 +0000
+signtype openpgp
+sign -----BEGIN PGP SIGNATURE-----%0a
+ Version: GnuPG v1.4.6 (GNU/Linux)%0a
+ %0a
+ iD8DBQBF0lGqwMbZpPMRm5oRAuRiAJ9ohBLd7s2kqjkKlq1qqC57SbnmzQCdG4ui%0a
+ nLE/L9aUXdWeTFPron96DLA=%0a
+ =2E+0%0a
+ -----END PGP SIGNATURE-----%0a
 
-GIT 1.5.0
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.6 (GNU/Linux)
 
-iD8DBQBF0lGqwMbZpPMRm5oRAuRiAJ9ohBLd7s2kqjkKlq1qqC57SbnmzQCdG4ui
-nLE/L9aUXdWeTFPron96DLA=
-=2E+0
------END PGP SIGNATURE-----
+GIT 1.5.0
 ------------------------------------------------
 
 See the linkgit:git-tag[1] command to learn how to create and verify tag
@@ -3702,9 +3704,9 @@ A tree can be created with linkgit:git-write-tree[1] and its data can be
 accessed by linkgit:git-ls-tree[1].  Two trees can be compared with
 linkgit:git-diff-tree[1].
 
-A tag is created with linkgit:git-mktag[1], and the signature can be
-verified by linkgit:git-verify-tag[1], though it is normally simpler to
-use linkgit:git-tag[1] for both.
+A tag is created with linkgit:git-mktag[1], and the cryptographic
+signature can be verified by linkgit:git-verify-tag[1], though it is
+normally simpler to use linkgit:git-tag[1] for both.
 
 [[the-workflow]]
 === The Workflow
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH v1 1/1] Modifies documentation for universal cryptographic signing
  2021-05-08  6:18 ` [RFC PATCH v1 1/1] Modifies documentation for universal " Dave Huseby
@ 2021-05-08  7:52   ` Bagas Sanjaya
  2021-05-09  0:16   ` brian m. carlson
  1 sibling, 0 replies; 4+ messages in thread
From: Bagas Sanjaya @ 2021-05-08  7:52 UTC (permalink / raw)
  To: Dave Huseby, git

On 08/05/21 13.18, Dave Huseby wrote:
> +In mergtags, the whole signed tag object is stored in the field name

Oops, s/mergtags/mergetags/

> +The `sign` field is very similar to the old `gpgsig` field in commits. The data
> +is can be multi-line with subsequent lines starting with spaces to mark them as
> +additional data. The only difference is that the `sign` field stores signatures
> +with newlines and carriage returns escaped because whitespace is significate in

Oops, s/significate/significant/

-- 
An old man doll... just what I always wanted! - Clara

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC PATCH v1 1/1] Modifies documentation for universal cryptographic signing
  2021-05-08  6:18 ` [RFC PATCH v1 1/1] Modifies documentation for universal " Dave Huseby
  2021-05-08  7:52   ` Bagas Sanjaya
@ 2021-05-09  0:16   ` brian m. carlson
  1 sibling, 0 replies; 4+ messages in thread
From: brian m. carlson @ 2021-05-09  0:16 UTC (permalink / raw)
  To: Dave Huseby; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 9419 bytes --]

On 2021-05-08 at 06:18:23, Dave Huseby wrote:
> Signed-off-by: Dave Huseby <dwh@linuxprogrammer.org>

You definitely need a commit message here explaining your approach and
justifying it.  I'm not saying that your approach is bad, but people
generally read the commit message to help understand and review the
commit, and we will want to know why you've made the decisions you've
made here and rejected other solutions, and the commit message will
hopefully explain that to us.

>  Signed Commits
>  ~~~~~~~~~~~~~~
> -We add a new field "gpgsig-sha256" to the commit object format to allow
> -signing commits without relying on SHA-1. It is similar to the
> -existing "gpgsig" field. Its signed payload is the SHA-256 content of the
> -commit object with any "gpgsig" and "gpgsig-sha256" fields removed.
> +We use the new signature format whenever signing commits without relying
> +on SHA-1. The new format adds a 'signtype' field, zero or more 'signoption'
> +fields, and one 'sign' field to commit objects. This allows for the 'gpgsig'
> +field to coexist if needed.
> 
>  This means commits can be signed
> 
>  1. using SHA-1 only, as in existing signed commit objects
> -2. using both SHA-1 and SHA-256, by using both gpgsig-sha256 and gpgsig
> -   fields.
> -3. using only SHA-256, by only using the gpgsig-sha256 field.
> +2. using both SHA-1 and SHA-256, by using both gpgsig and the V2 format.
> +3. using only SHA-256, by only using the V2 format.

SHA-256 repositories already exist and already use this format.  You
cannot change it now, since doing so will needlessly break commits.
Just because they are experimental doesn't mean we should break
compatibility needlessly.

>  Old versions of "git verify-commit" can verify the gpgsig signature in
>  cases (1) and (2) without modifications and view case (3) as an
> @@ -427,17 +426,16 @@ ordinary unsigned commit.
>  Signed Tags
>  ~~~~~~~~~~~
> -We add a new field "gpgsig-sha256" to the tag object format to allow
> -signing tags without relying on SHA-1. Its signed payload is the
> -SHA-256 content of the tag with its gpgsig-sha256 field and "-----BEGIN PGP
> -SIGNATURE-----" delimited in-body signature removed.
> +We use the new signature format whenever signing tags without relying
> +on SHA-1. The new format adds a 'signtype' field, zero or more 'signoption'
> +fields, and one 'sign' field to tag objects. This allows for the in-body
> +SHA-1 signature to coexist if needed.
> 
>  This means tags can be signed
> 
>  1. using SHA-1 only, as in existing signed tag objects
> -2. using both SHA-1 and SHA-256, by using gpgsig-sha256 and an in-body
> -   signature.
> -3. using only SHA-256, by only using the gpgsig-sha256 field.
> +2. using both SHA-1 and SHA-256, by using both gpgsig and the V2 format.
> +3. using only SHA-256, by only using the V2 format.

The same thing here.  This is currently out of date; we use signed tags
for the same algorithm (that is, for the SHA-1 signature of a SHA-1
object and for the SHA-256 signature of a SHA-256 object) and fields for
the other.

> +Version 2 Format
> +----------------
> +
> +The goals of the version 2 format are as follows:
> +
> +- Backwards Compatible with version 1 without any intervention.
> +- Eliminate signature-format-specific string matching for detecting/parsing
> +  version 2 signatures.
> +- Use fields for storing signatures in all objects and transactions.
> +- Have a field that identifies the signature format.
> +- Have fields that store options required by the verification tool.
> +- Store signature data verbatim as created with the signing tool with escaped
> +  newlines and carriage returns.

We probably need to define what happens if both a v1 and v2 signature
occur.  Probably the commit is invalid and should be rejected.

> +Fields
> +~~~~~~
> +
> +The version 2 format uses three new fields listed below:
> +
> +- signtype <signature format name>
> +- signoption <token> [= <value>]
> +- sign <multiline signature data>
> +
> +A complete signature must include exactly one `signtype` field, zero or more
> +`signoption` fields and one `sign` field.

This is going to be a problem.  We want to dual-sign objects over both
their SHA-1 and SHA-256 values.  We already have dual-signed objects in
the repository.

> +The `signtype` field has a string value that identifies the type of signature
> +that is stored in the object. This string is case-insensitive and is used to
> +identify which configuration settings are to used when verifying the signature.
> +The corresponding configuration settings are in the config file as:
> +'sign.<signType>.options.*'. The 'sign' field stores the text-encoded signature
> +from the signing tool with any newlines and carriage returns escaped as '%0a'
> +and '%0d' respectively. Whitespace is significant in digital signatures and
> +the protocol for sending/receiving data to/from signing and verification tools
> +requires that newlines and carriage returns are escaped. By storing the escaped
> +version in the 'sign' field, we avoid extra processing and error-prone
> +escaping.

Is there a reason we can't use the indented block format currently used
by gpgsig and friends?  Are there really formats that need to support
carriage returns in their signature?  If so, can we just specify those
algorithms will encode it with base64?

Also, it will be required to escape other values as well.  For example,
if you encode things with %, then you must escape %.  Git will also not
allow NUL bytes in commit objects, so if you want to encode arbitrary
binary data (which I would just do by requiring people to base64, but
you may not want to), you'll need to escape them as well.

> +The introduction of the 'signoption' field is necessary for Git to remain
> +agnostic to the tools used for signing and verification of cryptographic
> +signatures. Some signign tools do not produce cryptographic signatures that
> +include all of the data needed to verify the signature. A good example of this
> +is the minisign tool (https://jedisct1.github.io/minisign/) which requires the
> +public key to be supplied to the verification operation. In that case, the
> +signing operation would return to Git a 'signoption' field along with the
> +'signtype' and 'sign' fields to be stored in the Git object. When Git verifies
> +the signature, it will parse the 'signoption' fields and send them to the
> +verification tool as OPTION commands. In this case it will send the public key
> +along with the signature for verification. This design allows for arbitrary
> +options to be stored in the Git object by the signing tool that will get passed
> +to the verification tool later without Git knowing or understanding any details
> +of a particular signing tool.

While I'd like to see us support minisign, I have concerns about
embedding the public key in the signature.  First, that bloats commit
objects, and large commit objects can cause performance and scalability
problems.  Many things like partial clone implicitly assume that commits
and tags are small.

Second, the goal is presumably to verify that the signature identifies
some relevant party, not just some arbitrary user.  As a consequence, I
think it's safe to assume that we have a way to acquire the public key
of the trusted user whose signature we want to verify.

> +The order in which OPTION commands are sent to the signing and verification
> +tools is significant. OPTION commands that come later override OPTION commands
> +that came earlier and had the same token name. Git always sends OPTION commands
> +from the command line after the options from the config. In verification
> +operations, Git sends the options from the signed object first, before the
> +config and command line options. This ensures local control over option values.
> +An example would be if the sign.openpgp.options.minTrustLevel config option is
> +set to "marginal" and the command line `--sign-option minTrustLevel = full` is
> +issued. Git would first send an OPTION command setting
> +`minTrustLevel = marginal` from the config and then override that by later
> +sending an OPTION command setting `minTrustLevel = full` from the command line.

It's a security problem to allow people to control verification
parameters or command-line options.  The former allows users to validate
signatures using weak algorithms or reduced trust levels, and the latter
may allow arbitrary code execution.

Unless this field is going to be used for some signature parameter other
than public keys or verification parameters, I'd rather we omit it.  If
we keep it, the allowed parameters must be strictly defined and
documented per format and not allowed to contain arbitrary data.

Overall, I'm generally positive on this approach, although I think it
needs some further refinements as I've mentioned above.  My preference
is that we specifically document specific signature schemes and, if we
keep the options, which options are allowed.  For example, "minisign"
and "signify" are compatible, and by specifying and documenting
well-known formats, we avoid the problem where people end up writing
invalid commits by typoing the name in their config.
-- 
brian m. carlson (he/him or they/them)
Houston, Texas, US

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-05-09  0:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-08  6:18 [RFC PATCH v1 0/1] Universal cryptographic signing Dave Huseby
2021-05-08  6:18 ` [RFC PATCH v1 1/1] Modifies documentation for universal " Dave Huseby
2021-05-08  7:52   ` Bagas Sanjaya
2021-05-09  0:16   ` brian m. carlson

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).