Skip to content

git: Allow signing of commits - #376

Closed
aleb wants to merge 4 commits into
git-bug:masterfrom
aleb:sign
Closed

aleb wants to merge 4 commits into
git-bug:masterfrom
aleb:sign

Conversation

@aleb

@aleb aleb commented Apr 15, 2020

Copy link
Copy Markdown

We could add more ways of specifying a key, such as picking one from the
adopted identity, but for now with this change we allow users who know what
they are doing to sign their bug changes.

By simply passing "-S" to git commit-tree when "commit.gpgsign" is "true", we
use git's mechanism for key choosing which is either by the configured user
name and email OR by whatever is specified in "user.signingkey".

Comment thread repository/git_testing.go Outdated
Comment thread repository/git_testing.go Outdated
Comment thread repository/git_test.go
@aleb
aleb force-pushed the sign branch 2 times, most recently from 77b6399 to 5157125 Compare April 15, 2020 14:29
@aleb

aleb commented Apr 20, 2020 •

Copy link
Copy Markdown
Author

Do you want to review this by itself, or in the context of the entire keys add/rm/validation functionality? We do not plan other changes to this signing of the commits part.

@MichaelMure

Copy link
Copy Markdown
Contributor

Hey, sorry I've been quite disrupted lately.

Yes, this would be better with the entire thing. With only this it doesn't enable a lot while creating more failure opportunities so I'm wary of merging it without the rest. I'll do a quick review though.

Comment thread repository/git_test.go Outdated
Comment thread repository/git_testing.go Outdated
Comment thread repository/git_testing.go Outdated
Comment thread repository/git_testing.go Outdated
@aleb
aleb force-pushed the sign branch 4 times, most recently from 61f814d to ec2e986 Compare April 24, 2020 11:52

@MichaelMure MichaelMure left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, thanks for all that. Sorry for the lengthy review :)

Comment thread commands/select/select.go Outdated
Comment thread commands/key_add.go Outdated
Comment thread input/input.go Outdated
Comment thread identity/identity.go Outdated
Comment thread identity/identity.go Outdated
Comment thread identity/identity.go Outdated
Comment thread identity/key.go Outdated
Comment thread commands/key.go Outdated
Comment thread commands/key_add.go Outdated
}

if keyAddArmoredFile == "" && keyAddArmored == "" {
keyAddArmored, err = input.IdentityVersionKeyEditorInput(backend, "")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about generating a new key instead ? Ideally using git-bug, even with signature, should not require for the user to learn PGP or even knowing what that is. Power user should still be allowed to input their own keys but that's their choice to go the hard way.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generating a new key means the private key has to be stored in a file, and to be used with gpg it has to be imported. Can be done, but we can live without it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storing the private key in the git config, even is it's not perfect seems like an OK solution to me. It would be nice to be entirely independent of a gpg binary, but I don't know if that's possible without migrating to go-git.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be done, but can also be added later?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I'm not going to refuse this useful contribution because it doesn't meet 100% of what I think should happen but I'm considering that a requirement for an actual release.

I'm also saying that because it looks like that you are going on a more complicated path but I may be wrong.

@aleb aleb Apr 29, 2020 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do need gpg and the private key to be in the gpg keyring to be able to create signed (non-git-bug) commits with git.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I'll be happy when I can ditch the git CLI exec repo, it cause so many problems :(

@aleb aleb Apr 29, 2020 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the private key will be used also when signing the normal commits in the repository, so gpg will be used since creating those commits will be done with git, not with anything git-bug or go-git.

Comment thread commands/key_add.go Outdated
defer backend.Close()
interrupt.RegisterCleaner(backend.Close)

id, args, err := _select.ResolveUser(backend, args)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should only be able to add a key on a user you are allowed to control. There is two scenario where this is the case:

  • the identity has no key yet ("unprotected")
  • you have the private key of one of the public key present in the last version

This rules should be implemented in the Validate() function of Identity so they are checked 1) before a commit and 2) when merging remote data.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user loses the private key, the identity can't be used anylonger.

(In our case, we trust everybody to add/remove keys to anybody. The server ("when merging remote data"?) would run a custom check to make sure the keyring is valid and that everything originates from one key.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a notion of "admin identity"?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user loses the private key, the identity can't be used any longer.

Yes, that's the kind of hard rules you end up having with distributed applications. Some sort of backup or trust system could be imagined but for now that looks like the good way to go to me.

The server ("when merging remote data"?) would run a custom check to make sure the keyring is valid and that everything originates from one key.)

Why do you need code server side ? I understand you have different requirements, but is there a way for you to implement those extra requirements while staying close to git-bug's design as a distributed app ? It would help both of us if we can manage that.

Is there a notion of "admin identity"?

Not yet but that would be nice. To reach that point the plan is:

  • have a shared project config data structure (valid labels , .... )
  • store in that new structure who is admin, with the mechanism to update it
  • implement this admin role as rules to check when accepting new data (bugs + project config at least)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user loses the private key, the identity can't be used any longer.

Yes, that's the kind of hard rules you end up having with distributed applications. Some sort of backup or trust system could be imagined but for now that looks like the good way to go to me.

What would be the problem with trusting everybody to make changes to identities?

The server ("when merging remote data"?) would run a custom check to make sure the keyring is valid and that everything originates from one key.)

Why do you need code server side ? I understand you have different requirements, but is there a way for you to implement those extra requirements while staying close to git-bug's design as a distributed app ? It would help both of us if we can manage that.

The problem is the users can push anything working around the local validation done when they use git-ticket. The pre-receive server-side git hook prevents merging bad changes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the problem with trusting everybody to make changes to identities?

In the general case people that have a write access to a git repo are trustworthy but that's not always the case. Git support signature to be able to prove that someone made something and improve the trust you can have in the system, but if someone is able to change the valid keys of anyone else, this signature system is worth nothing.

In a similar fashion, this identity system will be the base of the role management. Some users will be admin of a project (or more complex roles) and some not. If you can tamper the keys of anyone, this system is equally useless.

If everyone is trustworthy it's all good and you don't even have to bother with keys and you can leave your identity unprotected. When it's not the case, you should be protected from abuse.

The problem is the users can push anything working around the local validation done when they use git-ticket. The pre-receive server-side git hook prevents merging bad changes.

Why is that the case ? If your user use git ticket pull (which is much simpler than manually merging remote hidden branches), data will be checked. Everything that doesn't follow the rules will be discarded.

My point is, even if a malicious user manage to push bad changes, those changes will not propagate. A non-malicious user should not be able to create bad data as it is checked before writing to git.

Now I agree that its not perfect and a server side hook to control the data is useful. Would you share the one you have ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huhu sorry, reading myself again, I realize I rewrote what you were saying.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signatures are useful to prove the changes have not been made by an authorized user pretending to be some other authorized user.

The valid keys can be changed by any authorized user, but it will be obvious who changed them, since the server shall not accept forced pushes.

The malicious authorized users can work around the local validation, but they shall not be allowed to push, because we can. :) Yes, I'll share the validator!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The valid keys can be changed by any authorized user, but it will be obvious who changed them, since the server shall not accept forced pushes.

Yes, you can do forensics to find out who dropped the ball, but it would be better to actually prevent it, no ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking out loud, there should probably be a Keystore interface somewhere with multiple implementations:

  • git config
  • gpg
  • some centralized system that allow recovery for "corporate" environment

Maybe even an implementation that allow to have multiple sub-keystore for example git config + gpg.

@MichaelMure

Copy link
Copy Markdown
Contributor

Not sure if you came across #130 and #55, have a look :)

@westurner

Copy link
Copy Markdown
Contributor

cc'ing from #383 "DOC,UBY: What do I specify for avatarURL? Gravatar? W3C DID?"

https://www.w3.org/TR/did-core/ ::

Decentralized identifiers (DIDs) are a new type of identifier that enables verifiable, decentralized digital identity. A DID identifies any subject (e.g., a person, organization, thing, data model, abstract entity, etc.) that the controller of the DID decides that it identifies. These new identifiers are designed to enable the controller of a DID to prove control over it and to be implemented independently of any centralized registry, identity provider, or certificate authority. DIDs are URLs that associate a DID subject with a DID document allowing trustable interactions associated with that subject. Each DID document can express cryptographic material, verification methods, or service endpoints, which provide a set of mechanisms enabling a DID controller to prove control of the DID. Service endpoints enable trusted interactions associated with the DID subject. A DID document might contain semantics about the subject that it identifies. A DID document might contain the DID subject itself (e.g. a data model).

This document specifies a common data model, a URL format, and a set of operations for DIDs, DID documents, and DID methods.

https://github.com/topics/decentralized-identifiers?l=go

https://github.com/decentralized-identity/github-did#what-can-i-do-with-my-did

Use your DIDs to test Linked Data Signatures, such OpenPgpSignature2019 which is currently being developed. When DID Documents are signed, they include a proof attribute, which is used to provide proof that someone controlled the private key associated with the public key listed in the did document at the created datetime.

@westurner

Copy link
Copy Markdown
Contributor

... GPG keyservers could also solve for PKI in a centralized way.

GitHub and GitLab already expose SSH and GPG public keys if they're added to a username:

GitLab

Keybase

@aleb

aleb commented May 7, 2020 •

Copy link
Copy Markdown
Author

@MichaelMure
I added a 3rd commit "Verify signed identities".

I'm not sure what verification logic would be common to git-bug and git-ticket (hah, good thing the name is different). I pushed the verification logic we'll use so you can have a look. It's not yet merged in git-ticket. If there is something common and reusable, I could separate the logic from this 3rd commit.

I introduced go-git to be able to read the commits to be verified. The go-git repo is added as repo2 along repo repository.ClockedRepo in RepoCache, could not come up with anything better.

The very first commit in the identities history is very important. It is of course a commit which creates a new identity. The validation logic requires the newly created identity to have a key and be signed with that key. As long as the commits are signed, it's not strictly necessary for the key to be introduced in the very first commit, but I changed git-bug user create to be able to specify a key and have it included in this first commit. When the identities are validated, the fingerprint of the first key is reported like this:

$ b validate
first commit signed with key: C77E1D7542889EC0E45BA88899DA3BE167DA2410

When checking a git reference in the main repo, the key introduced by the first commit guarantees that everything is coming from us.

I made a small change to Identity.Commit to increase the lamport time so each identity version has a different lamport time so they can be sorted. The logic requires the lamport time for each version introducing/removing keys to be distinct. This might bite us, but we'll see.

The validate logic then sorts the identity versions by lamport time and iterates them. A keyring is built gradually and used to verify each commit before applying the key changes to the keyring.

The keyring is built as an openpgp.EntityList which is just a list of openpgp.Entity. Each Entity holds a single key. Technically, we could use a single Entity per git-bug Identity and add multiple keys to it and revoke them, but I found it simpler to have each Entity responsible for a single key.

When building the keyring, the time of the commit adding the key ends up in Identity.SelfSignature.CreationTime. The time of the commit removing a key, if any, is used to calculate the key lifetime stored in Identity.SelfSignature.KeyLifetimeSecs. The creation time and the expiry time are used in verifyCommitSignature for checking both identities and normal commits (from the main repo). This means for identities both the lamport time and the unix time are checked.

I had to expose private fields such as Identity.Versions. Maybe it can be done more cleanly.

TODO: I should move at least identity/key_test.go to the previous commit, maybe some more small stuff.

We could have used key fingerprints instead of key ids to identify the keys, but it seemed simpler to use the key id. The key fingerprint is composed of the key id and some other bits.

TL;DR: The first two commits would make sense to merge into git-bug, maybe also some common part of validate functionality if any.

Please have a look.

Any requests?

@aleb

aleb commented May 8, 2020

Copy link
Copy Markdown
Author

@MichaelMure In light of our validation logic which will never make it into git-bug, could you please comment on the first two commits if they are roughly ok and could be merged in git-bug? Thanks.

@MichaelMure

MichaelMure commented May 8, 2020 •

Copy link
Copy Markdown
Contributor

Hey @aleb this is a pretty big change to review, it might take time for me to go through it.

As a preamble, I find that some of this code doesn't follow the architecture design ans "leak" through the layers. Two things comes to mind:

  • Key: all the tricky handling of keys, encoding, parsing should be abstracted behind the public interface of Key instead of spreading up to the commands. I made a tentative refactoring with 1e760c3 . It's not done, not everything compile, but it should at least give you the idea.
  • I'm yet to understand what this validation is, but the go-git thing should be in the repo package, Ideally behind the same Repo interface and in the same GitRepo implementation, even if that make a small Frankenstein here. The cache layer is really not meant for that. That would also be a first step towards migrating.

Speaking of this Validator thing, I'm a bit confused tbh, what is it for ? When is it supposed to run ? What should happen if the validation fail ? Why not stay with the Validate() functions everywhere and have a piece of code reload everything and validate through those ? Maybe Identity/Bug should also check the commit signature when loading the data ?

I'm not sure what verification logic would be common to git-bug and git-ticket

Unless I'm mistaken, both share a very similar need here, or at least we can find a common ground from where you can build your extra validations without breaking everything at each rebase. It seems to me that you want a different set of data/operations (Bug vs ticket) but the "framework" part could be largely shared.

The validation logic requires the newly created identity to have a key and be signed with that key.

git-bug will keep allowing identities without keys, but a flag somewhere to have a mode where they need to have at least one is entirely possible. Useful for both.

The very first commit in the identities history is very important. It is of course a commit which creates a new identity. The validation logic requires the newly created identity to have a key and be signed with that key.

Hmmm, when I originally thought about this the idea was, to add a key to an identity, add the private key in the version as well as a signature for the previous data. Here you are adding the signature in the commit itself, which is a bit different and tie git-bug more to git itself. Not sure what is the best way really. I need to think more about this.

I made a small change to Identity.Commit to increase the lamport time so each identity version has a different lamport time so they can be sorted.

Adding ordering to identities is fine, but that needs to be a distinct Lamport clock to not mess with the bugs. It looks like it's time to update the ClockedRepo to something simpler that support an arbitrary number of clocks. What about this:

// ClockedRepo is a Repo that also has Lamport clocks
type ClockedRepo interface {
	Repo

	GetClock(name string) Clock
}

type Clock interface {
	Time() lamport.Time
	Increment() (lamport.Time, error)
	Witness(time lamport.Time) error
}

And yes, it seems that LoadClocks and WriteClocks are never used outside of GitRepo itself so they should not be part of the interface. Cleanup time !

@MichaelMure

Copy link
Copy Markdown
Contributor

Hmmm, when I originally thought about this the idea was, to add a key to an identity, add the private key in the version as well as a signature for the previous data. Here you are adding the signature in the commit itself, which is a bit different and tie git-bug more to git itself. Not sure what is the best way really. I need to think more about this.

So I think this boils down to the question of whether or not rebase are needed. If the commit is signed by the author, rebasing and rearranging the commits is not possible anymore without invalidating the signature. If the data is signed, we are still free to do that.

In other words, if the commit is signed, the whole history is signed. If the data is signed, only this specific piece of data is signed, which only prove authorship (which is really nice already).

The problem is that at the moment, git-bug does make rebase when changes are pulled. Most of the time people use a unique central git repo so it could work because the commit that are rebased are your own, so you could sign them again. But as soon as you use more than one remote or push/pull directly this model fall apart.

What I was thinking about in #212 was to replace the rebase with merges to do the conflict resolution. This would make the data model entirely immutable and would combine very well with signing the commits.

So, short of doing this #212 (which would be awesome but a lot of work), the choice end up being either:

  1. explicitly saying that fully decentralized workflow is not supported
  2. working on the commit signing without fully enabling it yet and wait for the data model rework to complete
  3. do data signing and change to commit signing when the data model change is completed

I think option 2 make the most sense here. What do you think ?

@aleb

aleb commented May 15, 2020

Copy link
Copy Markdown
Author

Sorry for the late reply.

As a preamble, I find that some of this code doesn't follow the architecture design ans "leak" through the layers. Two things comes to mind:

  • Key: all the tricky handling of keys, encoding, parsing should be abstracted behind the public interface of Key instead of spreading up to the commands. I made a tentative refactoring with 1e760c3 . It's not done, not everything compile, but it should at least give you the idea.

I cherry-picked your commit and fix the issues.

  • I'm yet to understand what this validation is, but the go-git thing should be in the repo package, Ideally behind the same Repo interface and in the same GitRepo implementation, even if that make a small Frankenstein here. The cache layer is really not meant for that. That would also be a first step towards migrating.

Sounds good. Done.

Speaking of this Validator thing, I'm a bit confused tbh, what is it for ? When is it supposed to run ? What should happen if the validation fail ? Why not stay with the Validate() functions everywhere and have a piece of code reload everything and validate through those ? Maybe Identity/Bug should also check the commit signature when loading the data ?

An identity can't fully validate itself if we want to allow others to make changes to an identity. A separate validator is needed to keep track of what keys have been added and removed and when. (It would have been simpler if only the keys added by the identity can sign the identity's changes, like you wanted(?), but we wanted something more flexible.)

The validate command verifies that the keys are in good order and that the identity changes are properly signed with the keys available at that lamport time. It will be used for example on the server-side git hook to prevent pushing bad data to the repo.

I'm not sure what verification logic would be common to git-bug and git-ticket

Unless I'm mistaken, both share a very similar need here, or at least we can find a common ground from where you can build your extra validations without breaking everything at each rebase. It seems to me that you want a different set of data/operations (Bug vs ticket) but the "framework" part could be largely shared.

The more that can be shared, the better.

git-bug will keep allowing identities without keys, but a flag somewhere to have a mode where they need to have at least one is entirely possible. Useful for both.

What would be a good place to store this flag in the repo?

The very first commit in the identities history is very important. It is of course a commit which creates a new identity. The validation logic requires the newly created identity to have a key and be signed with that key.

Hmmm, when I originally thought about this the idea was, to add a key to an identity, add the private key in the version as well as a signature for the previous data. Here you are adding the signature in the commit itself, which is a bit different and tie git-bug more to git itself. Not sure what is the best way really. I need to think more about this.

I don't completely follow. Why add the private key in the version?

I'm thinking the commits need to be signed anyway, so then we use those signatures. The whole point for us is to have every commit signed (with the "valid keys").

I made a small change to Identity.Commit to increase the lamport time so each identity version has a different lamport time so they can be sorted.

Adding ordering to identities is fine, but that needs to be a distinct Lamport clock to not mess with the bugs. It looks like it's time to update the ClockedRepo to something simpler that support an arbitrary number of clocks. What about this:

// ClockedRepo is a Repo that also has Lamport clocks
type ClockedRepo interface {
	Repo

	GetClock(name string) Clock
}

type Clock interface {
	Time() lamport.Time
	Increment() (lamport.Time, error)
	Witness(time lamport.Time) error
}

And yes, it seems that LoadClocks and WriteClocks are never used outside of GitRepo itself so they should not be part of the interface. Cleanup time !

Ok, let me see..

@aleb

aleb commented May 15, 2020 •

Copy link
Copy Markdown
Author

Hmmm, when I originally thought about this the idea was, to add a key to an identity, add the private key in the version as well as a signature for the previous data. Here you are adding the signature in the commit itself, which is a bit different and tie git-bug more to git itself. Not sure what is the best way really. I need to think more about this.

So I think this boils down to the question of whether or not rebase are needed. If the commit is signed by the author, rebasing and rearranging the commits is not possible anymore without invalidating the signature. If the data is signed, we are still free to do that.

In other words, if the commit is signed, the whole history is signed. If the data is signed, only this specific piece of data is signed, which only prove authorship (which is really nice already).

It would be good to use git's signatures system if possible, to keep things simple.

The problem is that at the moment, git-bug does make rebase when changes are pulled. Most of the time people use a unique central git repo so it could work because the commit that are rebased are your own, so you could sign them again. But as soon as you use more than one remote or push/pull directly this model fall apart.

We'll use a single remote, so it would work for us. Good to know about the local rebasing when changes are pulled.

What I was thinking about in #212 was to replace the rebase with merges to do the conflict resolution. This would make the data model entirely immutable and would combine very well with signing the commits.

So, short of doing this #212 (which would be awesome but a lot of work), the choice end up being either:

  1. explicitly saying that fully decentralized workflow is not supported
  2. working on the commit signing without fully enabling it yet and wait for the data model rework to complete
  3. do data signing and change to commit signing when the data model change is completed

I think option 2 make the most sense here. What do you think ?

We are not interested in the fully decentralized workflow. I'm not sure about the data signing benefits, but it sounds complicated. Option 2 sounds great since we'll be able to use it already and when the data model is reworked we'll be compatible.

@MichaelMure

Copy link
Copy Markdown
Contributor

An identity can't fully validate itself if we want to allow others to make changes to an identity. A separate validator is needed to keep track of what keys have been added and removed and when. (It would have been simpler if only the keys added by the identity can sign the identity's changes, like you wanted(?), but we wanted something more flexible.)

The validate command verifies that the keys are in good order and that the identity changes are properly signed with the keys available at that lamport time. It will be used for example on the server-side git hook to prevent pushing bad data to the repo.

I still don't really get what you want to achieve, I going to guess you want to have some sort of centralized authority for identities. If so, why not have this centralized create the identities with 2 keys, one private to this authority, one given to the user. If you want to prevent the user to make changes to the identity, we could have two list of keys in an identity:

  • keys that allow full control
  • keys that only allow signing commits, bugs ... but not change the identity itself.

Or maybe we should go all in already and encode that with capabilities on each keys. That would be more extensible for the future.

That's a little change that could enable nice new usecases.

On a side note, maybe those keys should have an optional name ? That might help for complex schemes.

The more that can be shared, the better.

100%. It seems that we are aiming for a sort of framework to build decentralized app on top of git, where git-bug itself would just be an example. That's awesome.

git-bug will keep allowing identities without keys, but a flag somewhere to have a mode where they need to have at least one is entirely possible. Useful for both.

What would be a good place to store this flag in the repo?

For now, a hard-coded flag in the code would be good so we don't conflict each other. Later this could also be included in the project settings for optional enabling in git-bug.

I don't completely follow. Why add the private key in the version?

Not the private keys. I was thinking about adding the signature of the previous version with one of the valid keys but that's a flawed model. Your idea is better.

So to recap, the current idea is:

  • have a chain of commit, each of them hold a version
  • a version hold zero, one or many public keys
  • if the first version has at least one public key, the associated commit must be signed with one of those keys
  • after that, if the previous version has at least one public key, the commit of this new version must be signed with a key of the previous version. This new version doesn't have to keep the public key associated to the signature. This allow for key rotation an possibly removing entirely the keys (not sure that one would be a good thing, we can add a rule to disallow that).

Sounds good to you?

@MichaelMure

Copy link
Copy Markdown
Contributor

We are not interested in the fully decentralized workflow. I'm not sure about the data signing benefits, but it sounds complicated. Option 2 sounds great since we'll be able to use it already and when the data model is reworked we'll be compatible.

Option 2 it is!

@MichaelMure

Copy link
Copy Markdown
Contributor

FYI, I'm working on the architecture/framework changes that will make this and adding new entities (PR, config ...) easier. It also happen to make the creation of forked tool like git-ticket easier. Have a look at #411

Following closely will be a WIP PR for a go-git repository implementation, which would make signing way easier.

@MichaelMure

Copy link
Copy Markdown
Contributor

go-git repo PR: #412

@MichaelMure

Copy link
Copy Markdown
Contributor

@aleb FYI, something similar to your last changes already now exist in master: https://github.com/MichaelMure/git-bug/blob/master/repository/repo.go#L108

@aleb
aleb force-pushed the sign branch 2 times, most recently from 87d8bf5 to 2104d6b Compare July 22, 2020 14:30
@aleb

aleb commented Jul 22, 2020

Copy link
Copy Markdown
Author

Yes, I noticed too late because I started a while ago..

I rebased and I think I don't have other changes planned at the moment.

Anything we should be aware of if merging this in git-ticket, so we remain compatible with upstream?

@aleb

aleb commented Jul 22, 2020 •

Copy link
Copy Markdown
Author

.. other than the failing test. :D

EDIT: done

@MichaelMure

Copy link
Copy Markdown
Contributor

Anything we should be aware of if merging this in git-ticket, so we remain compatible with upstream?

Yes.

I've been increasingly convinced that the good way to go to ultimately implement all those features (identities, signatures, ACL ...) is to:

  • ditch the git CLI based Repo in favor of the go-git implementation (almost done in repository: go-git backed Repo #412): not only the CLI version is frustrating, but that will give an easier access to commit signatures and friends
  • augment the repo with https://github.com/99designs/keyring to have access to the system credential storage, with a fallback on an encrypted file with password
  • stop storing bridges credential in the global git config
  • store identities private keys there instead of using GPG: if I'm not mistaken that means that GPG can be avoided entirely

In addition, more refactoring is need in the Identity, to store one time reference per entity (see https://github.com/MichaelMure/git-bug/blob/master/identity/version.go#L24-L27). This is so that it can be possible to say what version of an identity is valid for what element of an entity (Bug's operation, Ticket's operation, Config, PullRequest ...).

With all that we should have something that allow git-bug to grow with more entities, let git-ticket implement its own entities with minimal conflict and have an easier time implementing signatures for everyone.

Btw, thanks for spearheading this effort, it helped a lot to define what was necessary and what needed to change.

@MichaelMure

Copy link
Copy Markdown
Contributor

What do you think of this plan btw?

@aleb

aleb commented Aug 3, 2020

Copy link
Copy Markdown
Author

I've been increasingly convinced that the good way to go to ultimately implement all those features (identities, signatures, ACL ...) is to:

  • ditch the git CLI based Repo in favor of the go-git implementation (almost done in repository: go-git backed Repo #412): not only the CLI version is frustrating, but that will give an easier access to commit signatures and friends

Great!

  • augment the repo with https://github.com/99designs/keyring to have access to the system credential storage, with a fallback on an encrypted file with password
  • store identities private keys there instead of using GPG: if I'm not mistaken that means that GPG can be avoided entirely

IIUC the system credential storage would be used to get the private keys for signing commits created by git-bug.

When creating normal commits in the repo, the git CLI will use GPG. Ideally the private keys from GPG can be used with 99designs/keyring.

  • stop storing bridges credential in the global git config

Sounds good.

In addition, more refactoring is need in the Identity, to store one time reference per entity (see https://github.com/MichaelMure/git-bug/blob/master/identity/version.go#L24-L27). This is so that it can be possible to say what version of an identity is valid for what element of an entity (Bug's operation, Ticket's operation, Config, PullRequest ...).

In this case sorting all the Identity Versions with sort.Sort(ByLamportTime(v.versions)) won't be possible anymore, but we'd still be able to establish an order since we know exactly which Identity Version created the operation. If an Identity is disabled/canceled, then the central authority would have to prevent accepting new commits signed by it.

I think we could work with this.

@MichaelMure

Copy link
Copy Markdown
Contributor

IIUC the system credential storage would be used to get the private keys for signing commits created by git-bug.

When creating normal commits in the repo, the git CLI will use GPG. Ideally the private keys from GPG can be used with 99designs/keyring.

Yes. keyring can store arbitrary secrets, as long as they can be serialized into a []byte. go-git still use GPG but it's golang.org/x/crypto/openpgp which will be much easier to work with than CLI tool that may or may not be there.

In this case sorting all the Identity Versions with sort.Sort(ByLamportTime(v.versions)) won't be possible anymore, but we'd still be able to establish an order since we know exactly which Identity Version created the operation. If an Identity is disabled/canceled, then the central authority would have to prevent accepting new commits signed by it.

Not sure why you need that. Versions within an identity already have an implied logical order defined by the order of the commits in git. It would be possible to order identities by creation or edition by adding two extra Lamport clocks there but I don't see much the use of that.

We could add more ways of specifying a key, such as picking one from the
adopted identity, but for now with this change we allow users who know what
they are doing to sign their bug changes.

By simply passing "-S" to `git commit-tree` when "commit.gpgsign" is "true", we
use git's mechanism for key choosing which is either by the configured user
name and email OR by whatever is specified in "user.signingkey".
This assures the versions have a strict order.
@aleb

aleb commented Sep 11, 2020

Copy link
Copy Markdown
Author

In this case sorting all the Identity Versions with sort.Sort(ByLamportTime(v.versions)) won't be possible anymore, but we'd still be able to establish an order since we know exactly which Identity Version created the operation. If an Identity is disabled/canceled, then the central authority would have to prevent accepting new commits signed by it.

Not sure why you need that. Versions within an identity already have an implied logical order defined by the order of the commits in git. It would be possible to order identities by creation or edition by adding two extra Lamport clocks there but I don't see much the use of that.

We need to be able to sort the Versions across all Identities. This way it's possible to check each version has been created by somebody with a valid key at the time.

I think we'll try with a lamport clock used only for Versions.

@aleb

aleb commented Sep 11, 2020

Copy link
Copy Markdown
Author

Anything from here you can use upstream at this point?

@MichaelMure

MichaelMure commented Sep 16, 2020 •

Copy link
Copy Markdown
Contributor

Sorry it took me a while to digest all that and figure out what would be the right thing to do.

I think we'll try with a lamport clock used only for Versions.

Make sense to me. That would be similar to the edit Lamport time for bugs. Might as well throw another for the creation to mirror Bug.

Anything from here you can use upstream at this point?

Yes, but not as it is currently I'm afraid (sorry about that). There is a lot of good things though.

As you can see in #412, the go-git repo is pretty much ready to be merged (one missing thing is a migration for the bridge credentials in https://github.com/MichaelMure/git-bug-migration/, so nothing that concern you). Notably this repo will allow for a much more native and direct access to everything signature related. Hopefully this also allow to do less in git-bug and delegate to go-git and openpgp.

Additionally, something I'd like changed in this PR is how things are located. As of now the signature validation code is built around the core instead of integrating with it. That is, have signature validation available within bug and identities. I believe changing that would have multiple benefits:

  • split the massive validate package into smaller and more understandable pieces: validating the whole repo would then just be iterating over all the entities and call the validation function
  • allow to validate individual entities if the need arise
  • critically, allow to validate the data while reading it and before merging remote updates

Does that make sense to you?

(also ideally this would be done in smaller digestible PRs that can be merged along the way to this goal)

Comment thread cache/repo_cache.go

// the cache of commits
muCommit sync.RWMutex
commits map[repository.Hash]*object.Commit

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that really useful? Maybe I'm missing something but it looks to me that once a commit is read for validation, it's not useful anymore as it won't be shared with any other identities.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it does not seem useful.

Comment thread identity/identity.go
}
}

func NewIdentityFull(name string, email string, login string, avatarUrl string) *Identity {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a key change for the identities would be to have a KeyringAtTime(time lamport.Time) openpgp.EntityList in identity.Interface. This could be used later with gogit's Commit.Verify function to let them figure out the correct key from the possible candidate valid at that time.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did introduce a lamport clock for identity versions, but for the regular commits we don't have any lamport time. This could be used only when checking the Identity/Version commits.

@MichaelMure

Copy link
Copy Markdown
Contributor

@aleb FYI, #532 bring a major update to the data model that should interest you:

This should make your adventure with git-ticket much easier if you migrate as well.

As such, I'll close this PR.

Even if your code here has not been merged, it has been a very useful contribution and what is in master now is better because of it. Thank you.

@MichaelMure MichaelMure closed this Apr 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants