From: Hans Jerry Illikainen <hidden> Date: 2019-11-16 18:07:05
As part of implementing signature verification for git clone, I decided
to refactor/unify the code for commit and merge verification to make it
reusable during clones.
This lead me to discover that git requires merge signatures to be
trusted (as opposed to TRUST_UNKNOWN or TRUST_NEVER). This is unlike
the behavior of verify-tag and verify-commit.
So, I figured that I'd make the minimum trust level configurable to make
the behavior of merge/commit/tag consistent. And while doing so, I
noticed that parse_gpg_output() in gpg-interface.c assumes that the
VALIDSIG status line has a field with a fingerprint for the primary key;
but that is only the case for OpenPGP signatures [1].
The consequence of that assumption is that the subsequent status line is
interpreted as the primary fingerprint for X509 signatures. I'm not
sure if the order is hardcoded in GnuPG, but in my testing the TRUST_
status line always came after VALIDSIG -- and that breaks the config
option to set a minimum trust level (not part of this patch):
,----
| $ git log -n1 --format="primary key: %GP" signed-x509
| gpgsm: Signature made 2019-11-16 14:13:09 using certificate ID 0xFA23FD65
| gpgsm: Good signature from "/CN=C O Mitter/O=Example/SN=C O/GN=Mitter"
| gpgsm: aka "committer@example.com"
| primary key: TRUST_FULLY 0 shell
`----
[1]: https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS
Hans Jerry Illikainen (1):
gpg-interface: limit search for primary key fingerprint
gpg-interface.c | 20 +++++++++++++++-----
t/t4202-log.sh | 6 ++++++
2 files changed, 21 insertions(+), 5 deletions(-)
--
2.24.0.156.g69483321b9.dirty
From: Hans Jerry Illikainen <hidden> Date: 2019-11-16 18:09:36
The VALIDSIG status line from GnuPG with --status-fd has a field that
specifies the fingerprint of the primary key that made the signature.
However, that field is only available for OpenPGP signatures; not for
CMS/X.509.
An unbounded search for a non-existent primary key fingerprint for X509
signatures results in the following status line being interpreted as the
fingerprint.
Signed-off-by: Hans Jerry Illikainen <redacted>
---
gpg-interface.c | 20 +++++++++++++++-----
t/t4202-log.sh | 6 ++++++
2 files changed, 21 insertions(+), 5 deletions(-)
From: Jonathan Nieder <hidden> Date: 2019-11-16 19:49:51
Hi,
Hans Jerry Illikainen wrote:
As part of implementing signature verification for git clone, I decided
to refactor/unify the code for commit and merge verification to make it
reusable during clones.
Thanks for writing this.
Most of the text in this cover letter would be useful to have in the
commit message. From the commit message alone, I could see that you
were fixing a bug, but I could not see the motivation or workflow it
is part of. If I were to later discover an issue triggered by this
commit, I wouldn't have enough information to weigh tradeoffs about
the right way to address such an issue.
Thanks and hope that helps,
Jonathan
This lead me to discover that git requires merge signatures to be
trusted (as opposed to TRUST_UNKNOWN or TRUST_NEVER). This is unlike
the behavior of verify-tag and verify-commit.
So, I figured that I'd make the minimum trust level configurable to make
the behavior of merge/commit/tag consistent. And while doing so, I
noticed that parse_gpg_output() in gpg-interface.c assumes that the
VALIDSIG status line has a field with a fingerprint for the primary key;
but that is only the case for OpenPGP signatures [1].
The consequence of that assumption is that the subsequent status line is
interpreted as the primary fingerprint for X509 signatures. I'm not
sure if the order is hardcoded in GnuPG, but in my testing the TRUST_
status line always came after VALIDSIG -- and that breaks the config
option to set a minimum trust level (not part of this patch):
,----
| $ git log -n1 --format="primary key: %GP" signed-x509
| gpgsm: Signature made 2019-11-16 14:13:09 using certificate ID 0xFA23FD65
| gpgsm: Good signature from "/CN=C O Mitter/O=Example/SN=C O/GN=Mitter"
| gpgsm: aka "committer@example.com"
| primary key: TRUST_FULLY 0 shell
`----
[1]: https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS
From: Hans Jerry Illikainen <hidden> Date: 2019-11-16 21:58:57
As part of implementing signature verification for git clone, I decided
to refactor/unify the code for commit and merge verification to make it
reusable during clones.
This lead me to discover that git requires merge signatures to be
trusted (as opposed to TRUST_UNKNOWN or TRUST_NEVER). This is unlike
the behavior of verify-tag and verify-commit.
So, I figured that I'd make the minimum trust level configurable to make
the behavior of merge/commit/tag consistent. And while doing so, I
noticed that parse_gpg_output() in gpg-interface.c assumes that the
VALIDSIG status line has a field with a fingerprint for the primary key;
but that is only the case for OpenPGP signatures [1].
The consequence of that assumption is that the subsequent status line is
interpreted as the primary fingerprint for X509 signatures. I'm not
sure if the order is hardcoded in GnuPG, but in my testing the TRUST_
status line always came after VALIDSIG -- and that breaks the config
option to set a minimum trust level (not part of this patch):
,----
| $ git log -n1 --format="primary key: %GP" signed-x509
| gpgsm: Signature made 2019-11-16 14:13:09 using certificate ID 0xFA23FD65
| gpgsm: Good signature from "/CN=C O Mitter/O=Example/SN=C O/GN=Mitter"
| gpgsm: aka "committer@example.com"
| primary key: TRUST_FULLY 0 shell
`----
[1]: https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS
Hans Jerry Illikainen (1):
gpg-interface: limit search for primary key fingerprint
gpg-interface.c | 20 +++++++++++++++-----
t/t4202-log.sh | 6 ++++++
2 files changed, 21 insertions(+), 5 deletions(-)
--
2.24.GIT
From: Hans Jerry Illikainen <hidden> Date: 2019-11-16 21:58:58
As part of implementing signature verification for git clone, I decided
to refactor/unify the code for commit and merge verification to make it
reusable during clones.
This lead me to discover that git requires merge signatures to be
trusted (as opposed to TRUST_UNKNOWN or TRUST_NEVER). This is unlike
the behavior of verify-tag and verify-commit.
So, I figured that I'd make the minimum trust level configurable to make
the behavior of merge/commit/tag consistent. And while doing so, I
noticed that parse_gpg_output() in gpg-interface.c assumes that the
VALIDSIG status line has a field with a fingerprint for the primary key;
but that is only the case for OpenPGP signatures.
The consequence of that assumption is that the subsequent status line is
interpreted as the primary fingerprint for X509 signatures. I'm not
sure if the order is hardcoded in GnuPG, but in my testing the TRUST_
status line always came after VALIDSIG -- and that breaks the
possibility of a configuration option to set a minimum trust level since
the TRUST_ line is consumed by VALIDSIG.
Signed-off-by: Hans Jerry Illikainen <redacted>
---
gpg-interface.c | 20 +++++++++++++++-----
t/t4202-log.sh | 6 ++++++
2 files changed, 21 insertions(+), 5 deletions(-)
From: Hans Jerry Illikainen <hidden> Date: 2019-11-21 23:43:44
As part of the process of implementing signature verification for git
clone, I decided to refactor/unify the code for commit and merge
verification to make it reusable during clones.
This lead me to discover that git requires merge signatures to be
trusted (as opposed to TRUST_UNKNOWN or TRUST_NEVER). This is unlike
the behavior of verify-tag and verify-commit.
So, I figured that I'd make the minimum trust level configurable to make
the behavior of merge/commit/tag consistent. And while doing so, I
noticed that parse_gpg_output() in gpg-interface.c assumes that the
VALIDSIG status line has a field with a fingerprint for the primary key;
but that is only the case for OpenPGP signatures [1].
The consequence of that assumption is that the subsequent status line is
interpreted as the primary fingerprint for X509 signatures. I'm not
sure if the order is hardcoded in GnuPG, but in my testing the TRUST_
status line always came after VALIDSIG -- and that breaks the config
option to set a minimum trust level (not part of this patch):
,----
| $ git log -n1 --format="primary key: %GP" signed-x509
| gpgsm: Signature made 2019-11-16 14:13:09 using certificate ID 0xFA23FD65
| gpgsm: Good signature from "/CN=C O Mitter/O=Example/SN=C O/GN=Mitter"
| gpgsm: aka "committer@example.com"
| primary key: TRUST_FULLY 0 shell
`----
As per suggestion from Hamano, I also introduced a helper function,
replace_cstring(). I wasn't sure whether to add it in a separate commit
or not, but the kind folks in #git-devel suggested I do.
[1]: https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS
Hans Jerry Illikainen (2):
gpg-interface: refactor the free-and-xmemdupz pattern
gpg-interface: limit search for primary key fingerprint
gpg-interface.c | 45 ++++++++++++++++++++++++++++++++-------------
t/t4202-log.sh | 20 ++++++++++++++++++++
2 files changed, 52 insertions(+), 13 deletions(-)
--
2.24.0.157.gba9f894af8
From: Hans Jerry Illikainen <hidden> Date: 2019-11-21 23:43:50
This commit introduces a static replace_cstring() function. This
function simplifies the continuous pattern of free-and-xmemdupz() for
GPG status line parsing.
The benefit of having it in a single helper function is that it helps
avoid the need for duplicate code that does the same thing. It also
helps avoid potential memleaks if parsing of new status lines are
introduced in the future.
Signed-off-by: Hans Jerry Illikainen <redacted>
---
gpg-interface.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
@@ -136,21 +147,18 @@ static void parse_gpg_output(struct signature_check *sigc)/* Do we have key information? */if(sigcheck_gpg_status[i].flags&GPG_STATUS_KEYID){next=strchrnul(line,' ');-free(sigc->key);-sigc->key=xmemdupz(line,next-line);+replace_cstring(&sigc->key,line,next);/* Do we have signer information? */if(*next&&(sigcheck_gpg_status[i].flags&GPG_STATUS_UID)){line=next+1;next=strchrnul(line,'\n');-free(sigc->signer);-sigc->signer=xmemdupz(line,next-line);+replace_cstring(&sigc->signer,line,next);}}/* Do we have fingerprint? */if(sigcheck_gpg_status[i].flags&GPG_STATUS_FINGERPRINT){next=strchrnul(line,' ');-free(sigc->fingerprint);-sigc->fingerprint=xmemdupz(line,next-line);+replace_cstring(&sigc->fingerprint,line,next);/* Skip interim fields */for(j=9;j>0;j--){
From: Hans Jerry Illikainen <hidden> Date: 2019-11-21 23:43:51
The VALIDSIG status line from GnuPG with --status-fd is documented to
have 9 required and 1 optional fields [1]. The final, and optional,
field is used to specify the fingerprint of the primary key that made
the signature in case it was made by a subkey. However, this field is
only available for OpenPGP signatures; not for CMS/X.509.
The current code assumes that the VALIDSIG status line always has 10
fields. Furthermore, the current code assumes that each field is
separated by a space (0x20) character.
If the VALIDSIG status line does not have the optional 10th field, the
current code will continue reading onto the next status line -- because
only 0x20 is considered a field separator, not 0xa. And this is the
case for non-OpenPGP signatures [1].
The consequence is that a subsequent status line may be considered as
the "primary key" for signatures that does not have an actual primary
key.
The solution introduced by this commit is to add 0xa as a bound for the
search for a primary key. The search for the 10th VALIDSIG field is
aborted as soon as it sees a newline character. This keeps the parser
from interpreting subsequent lines as the primary key.
[1] https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS#l483
Signed-off-by: Hans Jerry Illikainen <redacted>
---
gpg-interface.c | 24 +++++++++++++++++-------
t/t4202-log.sh | 20 ++++++++++++++++++++
2 files changed, 37 insertions(+), 7 deletions(-)
From: Hans Jerry Illikainen <hidden> Date: 2019-11-22 20:23:20
As part of the process of implementing signature verification for git
clone, I decided to refactor/unify the code for commit and merge
verification to make it reusable during clones.
This lead me to discover that git requires merge signatures to be
trusted (as opposed to TRUST_UNKNOWN or TRUST_NEVER). This is unlike
the behavior of verify-tag and verify-commit.
So, I figured that I'd make the minimum trust level configurable to make
the behavior of merge/commit/tag consistent. And while doing so, I
noticed that parse_gpg_output() in gpg-interface.c assumes that the
VALIDSIG status line has a field with a fingerprint for the primary key;
but that is only the case for OpenPGP signatures [1].
The consequence of that assumption is that the subsequent status line is
interpreted as the primary fingerprint for X509 signatures. I'm not
sure if the order is hardcoded in GnuPG, but in my testing the TRUST_
status line always came after VALIDSIG -- and that breaks the config
option to set a minimum trust level (not part of this patch):
,----
| $ git log -n1 --format="primary key: %GP" signed-x509
| gpgsm: Signature made 2019-11-16 14:13:09 using certificate ID 0xFA23FD65
| gpgsm: Good signature from "/CN=C O Mitter/O=Example/SN=C O/GN=Mitter"
| gpgsm: aka "committer@example.com"
| primary key: TRUST_FULLY 0 shell
`----
As per suggestion from Hamano, I also introduced a helper function,
replace_cstring().
This patch revision fixes the indentation in the test cases as well as
an erroneous const qualification.
[1]: https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=6ce340e8c04794add995e84308bb3091450bd28f;hb=HEAD#l483
Hans Jerry Illikainen (2):
gpg-interface: refactor the free-and-xmemdupz pattern
gpg-interface: limit search for primary key fingerprint
gpg-interface.c | 44 ++++++++++++++++++++++++++++++++------------
t/t4202-log.sh | 20 ++++++++++++++++++++
2 files changed, 52 insertions(+), 12 deletions(-)
--
2.24.GIT
From: Hans Jerry Illikainen <hidden> Date: 2019-11-22 20:23:25
This commit introduces a static replace_cstring() function. This
function simplifies the continuous pattern of free-and-xmemdupz() for
GPG status line parsing.
The benefit of having it in a single helper function is that it helps
avoid the need for duplicate code that does the same thing. It also
helps avoid potential memleaks if parsing of new status lines are
introduced in the future.
Signed-off-by: Hans Jerry Illikainen <redacted>
---
gpg-interface.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
@@ -136,21 +146,18 @@ static void parse_gpg_output(struct signature_check *sigc)/* Do we have key information? */if(sigcheck_gpg_status[i].flags&GPG_STATUS_KEYID){next=strchrnul(line,' ');-free(sigc->key);-sigc->key=xmemdupz(line,next-line);+replace_cstring(&sigc->key,line,next);/* Do we have signer information? */if(*next&&(sigcheck_gpg_status[i].flags&GPG_STATUS_UID)){line=next+1;next=strchrnul(line,'\n');-free(sigc->signer);-sigc->signer=xmemdupz(line,next-line);+replace_cstring(&sigc->signer,line,next);}}/* Do we have fingerprint? */if(sigcheck_gpg_status[i].flags&GPG_STATUS_FINGERPRINT){next=strchrnul(line,' ');-free(sigc->fingerprint);-sigc->fingerprint=xmemdupz(line,next-line);+replace_cstring(&sigc->fingerprint,line,next);/* Skip interim fields */for(j=9;j>0;j--){
From: Hans Jerry Illikainen <hidden> Date: 2019-11-22 20:23:28
The VALIDSIG status line from GnuPG with --status-fd is documented to
have 9 required and 1 optional fields [1]. The final, and optional,
field is used to specify the fingerprint of the primary key that made
the signature in case it was made by a subkey. However, this field is
only available for OpenPGP signatures; not for CMS/X.509.
If the VALIDSIG status line does not have the optional 10th field, the
current code will continue reading onto the next status line. And this
is the case for non-OpenPGP signatures [1].
The consequence is that a subsequent status line may be considered as
the "primary key" for signatures that does not have an actual primary
key.
The solution introduced by this commit is to limit the search for a
primary key to a single line. The search for the 10th VALIDSIG field is
aborted as soon as it sees a newline character. This keeps the parser
from interpreting subsequent lines as the primary key.
[Reference]
[1] GnuPG Details, General status codes
https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=6ce340e8c04794add995e84308bb3091450bd28f;hb=HEAD#l483
The documentation say:
VALIDSIG <args>
The args are:
- <fingerprint_in_hex>
- <sig_creation_date>
- <sig-timestamp>
- <expire-timestamp>
- <sig-version>
- <reserved>
- <pubkey-algo>
- <hash-algo>
- <sig-class>
- [ <primary-key-fpr> ]
This status indicates that the signature is cryptographically
valid. [...] PRIMARY-KEY-FPR is the fingerprint of the primary key
or identical to the first argument.
The primary-key-fpr parameter is used for OpenPGP and not available
for CMS signatures. [...]
Signed-off-by: Hans Jerry Illikainen <redacted>
---
gpg-interface.c | 24 ++++++++++++++++++------
t/t4202-log.sh | 20 ++++++++++++++++++++
2 files changed, 38 insertions(+), 6 deletions(-)