
Welp, there go my Git signatures - CaliforniaKarl
http://karl.kornel.us/2017/10/welp-there-go-my-git-signatures/
======
hdhzy
Signing new commit with new subkey on top of all others is a valid strategy to
deal with this problem. Another would be creating new tag and signing it with
the new subkey.

For me it's not a problem that old commits are signed with revoked keys, there
are several ways one can get old broken signatures (e.g. key rotation) and by
design they should not be trusted.

One interesting voice in signing all commits by Linus:

> Signing each commit is totally stupid. It just means that you automate it,
> and you make the signature worth less. It also doesn't add any real value,
> since the way the git DAG-chain of SHA1's work, you only ever need _one_
> signature to make all the commits reachable from that one be effectively
> covered by that one. So signing each commit is simply missing the point.

Source: [http://git.661346.n2.nabble.com/GPG-signing-for-git-
commit-t...](http://git.661346.n2.nabble.com/GPG-signing-for-git-commit-
td2582986.html)

Also, depending one one's threat model signing all commits can still be not
sufficient:
[https://github.com/git/git/commit/a85b377d0419a9dfaca8af2320...](https://github.com/git/git/commit/a85b377d0419a9dfaca8af2320cc33b051cbed04)

~~~
3pt14159
The DAG-chain argument is kinda valid but misses the core point: I don't
validate an entire codebase every time I commit. I just validate the diff. If
later on a commit comes into the codebase that has some sort of evil action
then it means that a host of possible scenarios can be ruled out (such as
someone else easily faking the commit as me).

But if you want to get my key you have to get into my dev machine. There is a
class of people that can do that, but it substantially raises the bar. Really
what I would like is to make it so my Github account only accepts signed
commits, so that it is impossible to impersonate me without my key.

~~~
hdhzy
> I don't validate an entire codebase every time I commit.

Linus' point is that you don't need to validate the entire code base, if you
have one signed commit then everything that is "below" is also (implicitly)
signed. For example you can have a feature branch that has many small commits
and one merge commit that joins feature branch with master and you just need
to sign the merge commit to make sure all of these small commits are OK.

~~~
stouset
> Linus' point is that you don't need to validate the entire code base, if you
> have one signed commit then everything that is "below" is also (implicitly)
> signed.

And Linus is missing the point entirely.

Yes, signing a commit implicitly signs the repo all the way back to its
beginning. But when I'm actually performing the action of signing this commit,
_I am not actually going back through every commit and verifying them_.

The fact that you can use the properties of commit hashes to verify a chain
all the way back to the origin of the repo is irrelevant, because that's not
what someone actually signing a commit is intending or should be expected to
do.

When I'm signing a commit, I'm vouching that I am responsible for applying
_this set of changes_ to a given state of a repo. It says nothing about my
belief in the validity of changes to the repo made before it.

~~~
hdhzy
> When I'm signing a commit, I'm vouching that I am responsible for applying
> this set of changes to a given state of a repo. It says nothing about my
> belief in the validity of changes to the repo made before it.

Then you should be signing a diff not a commit. Signing a commit represents
something different, because commit references both the current tree (all
files) and parent commit you're basically vouching for all history and all
files.

For reference, git commit structure [0]:

    
    
        $ git cat-file -p ca82a6dff817ec66f44342007202690a93763949
        tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
        parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
        author Scott Chacon <schacon@gmail.com> 1205815931 -0700
        committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
    
        changed the version number
    

[0]: [https://git-scm.com/book/en/v2/Git-Internals-Transfer-
Protoc...](https://git-scm.com/book/en/v2/Git-Internals-Transfer-Protocols)

~~~
Ajedi32
That's ridiculous. If I signed a statement saying "The file with this hash is
malware: <hash here>" would you say that "you're basically vouching for that
file" just because my statement contained the file's hash?

Similarly, if I sign a commit containing `parent
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7`, that says nothing about whether I
consider all previous commits to be valid. It only says that the commit I just
signed was created based off of that parent commit, and that in order to see
the changes I actually made you'll need to diff against that parent. (Which
`git show <my commit id>` will do automatically.)

~~~
hdhzy
I think I used the word vouch incorrectly. When you sign a commit you indicate
that your changes can be applied only on that particular parent even if all
files or diffs were bit for bit identical. If it didn't work like that someone
could take your work and place it in a completely different project and claim
it was signed by you.

Note that even with signed commits there are same gaps in the system. For
example without signed pushes someone can take your signed commit from branch
"test" an push it to "master".

------
kanzure
> I don’t have a record of every signature I made

Use opentimestamps git wrapper. Each commit is signed and timestamped. When
you revoke your key, the original signed commit is still timestamped,
presumably before your revocation date.

[https://github.com/opentimestamps/opentimestamps-
client](https://github.com/opentimestamps/opentimestamps-client)

[https://opentimestamps.org/](https://opentimestamps.org/)

~~~
CaliforniaKarl
Dude. That looks awesome. It kindof annoys me that the timestamp wasn't
somehow worked into the signature itself (like as a sub-packet), but that
would probably need messing with GPG in some way.

(What I mean is, a GPG signature includes a space for "sub-packets" of
information, stored in in "length-type-value" form. See RFC 4480 Section 5.2.3
for the overall signature packet format. The OpenTimestamp data could be
embedded as a sub-packet, causing its content to also be signed.)

It looks like this site was posted 12 days ago by handpickednames in
[https://news.ycombinator.com/item?id=15456521](https://news.ycombinator.com/item?id=15456521),
but it didn't get must attention. I think people should check it out!

(Disclaimer: I don't have any position in Bitcoin or blockchain right now.)

~~~
hdhzy
> It kindof annoys me that the timestamp wasn't somehow worked into the
> signature itself (like as a sub-packet),

Interesting, I took a sample signature from here [0], saved that to file and
run `gpg --list-packets gitsig.asc`:

    
    
        # off=0 ctb=89 tag=2 hlen=3 plen=284
        :signature packet: algo 1, keyid 5D3EB2F8800430EB
            version 4, created 1399174181, md5len 0, sigclass 0x00
            digest algo 2, begin of digest 65 b4
            hashed subpkt 2 len 4 (sig created 2014-05-04)
            subpkt 16 len 8 (issuer key ID 5D3EB2F8800430EB)
            data: [2047 bits]
    

It looks like it is timestamped with date 2014-05-04T03:29:41.000Z. The tag
itself also has Date header, usually the tag is created and signed at the same
time.

[0]: [https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work](https://git-
scm.com/book/en/v2/Git-Tools-Signing-Your-Work)

OpenTimestamps protects against someone backdating signatures. If they control
the key they can create signatures with arbitrary dates but they can't put
them in the blockchain in any place. So basically that gives "proof of
existence" that the given signature existed at least at that exact point of
time. Disclaimer: I never used OpenTimestamps but rather Bitcoin Core JSON
interface to timestamp things (it's 3 simple commands to publish OP_RETURN
transaction).

For people that don't want to spend Bitcoin on timestamping it is possible to
(ab)use Certificate Transparency logs for the same purpose:
[https://wiki.mozilla.org/Security/Binary_Transparency](https://wiki.mozilla.org/Security/Binary_Transparency)

~~~
petertodd
> For people that don't want to spend Bitcoin on timestamping it is possible
> to (ab)use Certificate Transparency logs for the same purpose:
> [https://wiki.mozilla.org/Security/Binary_Transparency](https://wiki.mozilla.org/Security/Binary_Transparency)

To be clear, OpenTimestamps doesn't require you to spend money to create a
timestamp, as it has a set of public calender servers that pool timestamp
requests, allowing all OTS users to share the same BTC transaction (which
itself is paid out of donations).

------
eridius
Maybe Git could leverage git-notes as a mechanism for allowing re-signing
commits without changing the hashes.

~~~
hdhzy
That exactly how one can put multiple signatures on a commit.

~~~
satbyy
Could you plz provide an example ?

~~~
hdhzy
Check out Notes Towards Detached Signatures in Git [0].

[0]: [https://grimoire.ca/git/detached-sigs](https://grimoire.ca/git/detached-
sigs)

~~~
CaliforniaKarl
That's interesting! You should post that to HN directly, since it hasn't been
posted before.

~~~
hdhzy
Git's underlying data model is simple yet extremely flexible (see e.g. [0]),
well just like OpenPGP I guess.

As for the article you're welcome to post it yourself :)

[0]: [https://github.com/google/git-appraise](https://github.com/google/git-
appraise)

------
jwilk
> I don’t have a record of every signature I made.

Somebody please make a search engine for public OpenPGP signatures.

~~~
Karunamon
That’s basically a key server isn’t it? pgp.mit and others

~~~
jwilk
I want to find all signatures made by key
CDB5A1243ACDB63009AD07212D4EB3A6015475F5.

How does a key server help me?

------
cuckcuckspruce
Why would you have a shared SSH authentication key and PGP signing key? That
just seems like a really silly idea, and leads to having to deal with
situations like this.

Logging into a system remotely is a much different activity than signing a
file.

~~~
CaliforniaKarl
This is the awesome part, they're actually separate keys, with separate
policies!

(Or, well, separate sub-keys.)

With GPG, the only key that _has_ to be used for signing is the master key,
the first key that appears in a user's key listing. For all other sub-keys,
each key is explicitly marked as having a specific purpose.

Unfortunately, it doesn't look like you can see it on a public key server, but
you can see this yourself if you have GPG, using these two commands:

gpg --keyserver pgp.mit.edu --recv-keys e5e5afc8 gpg -k e5e5afc8

(You might not need the `--keyserver pgp.mit.edu` part, if you have a
keyserver specified already in your ~/.gnupg/gpg.conf file.)

(Also, I'm using GPG version 2.2.0. Older versions might not show the same
content. For example, GPG 1.4.16 does not.)

The first line of output from the second command should be this:

    
    
        pub   rsa4096 2015-12-13 [SC] [expires: 2025-12-10]
    

That's my public key, the main part of the key, and it is only able to be used
for signing stuff (the `S`), and for binding other sub-keys to the public key
(the `C`).

Later on, you have entries like this:

    
    
        sub   rsa4096 2015-12-13 [E] [expires: 2025-12-10]
        sub   rsa4096 2017-10-21 [A] [expires: 2019-04-14]
        sub   rsa4096 2017-10-21 [S] [expires: 2019-04-14]
    

Each of those lines represents a subkey, with an explicit purpose. The first
sub-key is for encryption/decryption of stuff, the second for authentication,
and the third for signing.

The signing sub-key is what was generated on my Yubikey, and is used for
signing stuff like email and Git commits. The authentication sub-key was
_also_ generated on my Yubikey, and is what gets transformed into an SSH key.

So, each sub-key is a key in its own right. The only common things between
them are that they are bound into the same GPG public key, and they are
contained on the same physical device.

One important thing to note, though, is that the OpenPGP Card standard (which
the Yubikey implements) has an optional flag, which requires the PIN every
time you do a signature. So, for me, the authentication key is like a local
agent-stored SSH key: You "unlock" it once, and then it works for a while
before you have to re-enter the PIN. But for signing, I have to re-enter the
PIN every time.

So yes, different activities, each with a key explicitly marked for that
activity, with different policies as to how I can access it.

~~~
jlgaddis
Assuming your encryption subkey was also generated on the YubiKey, why did you
not replace it as well?

~~~
CaliforniaKarl
My encryption subkey was explicitly _not_ generated inside the Yubikey. That
was an intentional choice; I chose to sacrifice some security by generating
the key in software and transferring it to the Yubikey, in exchange for the
convenience of having the ability to do so again in the future. I made that
choice because the encryption subkey is the one kind of subkey where I do not
have full control over its use.

What I mean is (for people still getting into this PGP stuff), with the
signing and authentication subkeys, I'm the one who is performing those
actions (ignoring things like compromised keys). For encryption, the sender is
the one who chooses which of the encryption subkeys to use, and there is no
way for me to be sure that their copy of my public key is up-to-date.

(Totally off-the-rails side note: For anyone who works with Kerberos, and
aliases/CNAMEs, you also have to deal with this problem, because it's the
client who chooses exactly which service principal to request a ticket for.)

I know that my current encryption subkey isn't going to last forever, but I
wanted to be able to use it on multiple "cards" (or in this case, a Yubikey).

~~~
hdhzy
For reference for other people this is called Key Escrow [0].

[0]:
[https://en.wikipedia.org/wiki/Key_escrow](https://en.wikipedia.org/wiki/Key_escrow)

~~~
CaliforniaKarl
I don't think it is exactly key escrow, because there is no third-party
involved. I generated my own keys for my own use, and nobody has access to
them (that I know of).

I know this might just be a semantic argument, but the Wikipedia article
linked is a good example of how controversial proper key escrow (involving a
third party) is.

If I'd refer people to a Wikipedia article, the article on Key Management
([https://en.wikipedia.org/wiki/Key_management](https://en.wikipedia.org/wiki/Key_management))
might be a better one, as it is more general, and my blog post touches on many
key management topics.

------
qznc
> every commit after this one will make it harder for someone to go back and
> change the note

Maybe you should also add some proof of work and make your commit hashes start
with certain patterns?

