redrabbit / git.limo

A Git source code management tool powered by Elixir with easy installation & high extensibility.
https://git.limo
MIT License
497 stars 42 forks source link

Implement parser for OpenPGP Message Format #40

Closed ghost closed 5 years ago

ghost commented 5 years ago

File type is : PGP/GPG key public ring (v4) created Thu May 3 22:35:56 2018 RSA (Encrypt or Sign) 2048 bits MPI=0xb33dca8fc4b3b174...

https://davesteele.github.io/gpg/2014/09/20/anatomy-of-a-gpg-key/

There may be a library to decode it's fields built into beam or maybe pick it apart using binary pattern matching.

ghost commented 5 years ago

I'll try and get this library resurected - https://github.com/esl/egpgme . I've got an open issue and PR trying to get it working https://github.com/sa2ajj/egpgme/pull/1 . If I can get it running, would you be interested in a PR? It's LGPL (unavoidable given the GPL code of gpgme library) - is that an issue. Alternatively - could have a go at creating a parser for the GPG export format.

redrabbit commented 5 years ago

Hi @bryanhuntesl, I did not have time to implement RFC 4880 - OpenPGP Message Format in order to parse GPG public keys and extract mandatory fields (key-id, subkeys, emails, etc.) so far.

I would prefer to not pull an external dependency such as gpgme and instead write the parser using pattern matching (see RFC 4880).

In order to show a "Verified" label for a each sign commit in a performant manner, we

1) Parse the gpgsig header from each commit in GitGud.RepoStorage.push/2, extract relevant informations and store them in the GitGud.Commit helper schema.

2) When rendering commits (and their "Verified" label), we retrieve their GPG key-id and match them against our GitGud.GPGKey schema. Similar to what we do to verify author's email addresses.

redrabbit commented 5 years ago

I've made a first attempt to display "Verified" commits. See 69f1e99.

The current implementation is weak and does not provide any checks in order to verify the commit's raw data with the associated public key. We basically only store GPG key ids on push and use them in order to match GitGud.GPGKey and associated GitGud.User when listing commits.

Currently, a commit is "Verified" only if the commit's author matches the user that signed the commit...


I'm not sure how GitHub or GitLab are verifying signed commits. I assume that they require to associate a verified email address to the public GPG key (which is easy to implement in our case). see 3292bde.

I'm also pretty sure that they verify the commit's raw data with the public key but I'm not sure when this occurs. Having to do so for each rendered commit will not perform well.

We could add a :signed_by field to GitGud.Commit and use it instead of :gpg_key_id when rendering commits. If we do so, we will have to implement commit verification (verify commit's raw data with the public key and set :signed_by) when

1) a commit is pushed (GitGud.RepoStorage.push/2) - retrieve the GPG key matching :gpg_key_id, verify the commit and set :signed_by field. 2) a GPG key is added - retrieve commits signed with the GPG key, verify them and set :signed_by accordingly.


I also know very little about GPG sub-keys and how hard it would be to support commit signing via subkeys.

redrabbit commented 5 years ago

We still need to calculate the fingerprint of :pubk and :pubsubk.

These fields are not stored as such within the OpenPGP Message Format. We need to calculate their fingerprint using a 160-bit SHA1 hash of the key and it meta-data (see Key IDs and Fingerprints).

A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99, followed by the two-octet packet length, followed by the entire Public-Key packet starting with the version field. The Key ID is the low-order 64 bits of the fingerprint. Here are the fields of the hash material, with the example of a DSA key:

a.1) 0x99 (1 octet)

a.2) high-order length octet of (b)-(e) (1 octet)

a.3) low-order length octet of (b)-(e) (1 octet)

b) version number = 4 (1 octet);

c) timestamp of key creation (4 octets);

d) algorithm (1 octet): 17 = DSA (example);

e) Algorithm-specific fields.

redrabbit commented 5 years ago

Closing this. I've open #42 for further work.