So today I'm going to talk about Sequoia Git, which is a tool for making signed commits matter.
And I'm sure that a lot of people in this room, you're here, you're want to hear about
signed commits.
You sign your commits, right?
How many people do?
A lot of people sign your commits, oh, about more than half, 60 percent.
That's great.
Do you know why you sign your commits?
No.
Nobody knows why they signed their commits.
Maybe I didn't give you enough time to raise your hand.
So what a version control systems do, because we all work with version control systems primarily
get they track changes.
They track the changes to the code.
They track 15 minutes left.
Okay.
They track changes to code.
They track authorship.
They track other metadata, like when you committed it, and they track, of course, the
commit message.
And we have a problem, because the author can actually be faked, who decides who the author
is.
It's the person who commits it.
So the person who commits goes ahead, says, oh, it's whoever, not me, for instance, I
could go ahead and create a commit from Linux.
I use Git Config to set his email address, his name.
I modify a few files, I add a commit, improve build, definitely does not add a backdoor,
very inspiring commit message.
And then I commit it.
And it's good.
It says, when we look at the log, it was by Linux Torvauds.
And believe it or not, Git Hub will even show it.
If you look at the picture over here, you'll see that Linux Torvauds has committed to my
repository.
Git Hub says it must be true.
Now GitHub knows who pushed the commit.
It was me.
I pushed it.
And the person I'm logged in, so that's why GitHub knows.
But the committer and the author are different, and couldn't GitHub go ahead and correct
that.
And the answer is no, because we want attribution, right?
That's one of the important things in the free and open source world is that the person
who does it gets the attribution.
At the same time, it's not only about attribution, it's also about blame, Git blame.
If somebody comes along, it does something bad.
And we want to be able to look at their other commits as well.
So in personation is bad, why do we care about it?
Well, maybe you have a project that's hosted on the forge, and the forge decides to insert
a back door.
Maybe they were forced to buy some three-letter agency.
How do we catch up?
Or maybe your project is hosted on the forge, and your account is compromised, so that
could happen.
And the attacker adds a commit, and they insert a back door into your project.
But we prevented, how do we detect it?
Or maybe there's somebody out there who's submitting patches on your behalf, like I just
did for a Linux, and it's a low quality patch, because it didn't actually fix the
build system.
It introduced the back door.
What do you do?
Did I damage Linux's reputation?
Well, probably not, in this case, but other people, how do we catch up?
Well, preventing impersonations, digitally signed commits.
We have cryptographic proof.
Thank you very much.
It was a pleasure to be here.
No, the signing is the easy part, right?
We already saw that two-thirds of the room does the signing, but nobody knows why we do
the signing.
So why?
Yeah, we can sign.
But again, we have the same problem as we had before.
Anybody can create a certificate with anybody's name.
I can go ahead.
I can create a certificate for Linus Torvals.
Here it is.
Generate, boom.
OpenPQP certificate with the user ID that Linus uses.
Okay, so we want to know, is this really Linus's certificate?
And the answer is, of course, no, because I just generated it, right?
You're all following along.
What about, so how do we authenticate these certificates?
Well, we can talk to the developer.
So if you happen to be here, I've lost them, and you go to the cubes stand.
You might see Martha there, and she's wearing her t-shirt, and at the bottom of it is
the OpenPQP fingerprint for the release key for cubes.
So you could take a picture of her or you could go online on YouTube.
You could talk to other people, and you could figure out what are their release keys.
That's good way to do it.
You could go to a key signing party.
We used to have key signing parties that fall some, not so much anymore.
There are centralized authorities.
For instance, there's keys.openpcp.org, which is a verifying key server.
They verify that you actually control the email address, so it's similar to, for instance,
that's encrypt.
We have the Linux kernel developer key ring.
You can go there onto the website.
You can download the key ring.
It's included in some distributions.
There's the distribution Gpg keys, package, which contains all of the certificates for
all of the different distributions, or most of them at least.
You could even use GitHub if you trust GitHub, GitHub.com slash user handle.chpc, and
boom, you get the certificate.
So there are a lot of different ways you can do this, and preferably you do multiple ways,
and you have multi-path, and then it's harder for an attacker to intercept it.
By the way, this is Linux's certificate.
Now we want to authenticate a project.
We can get a certificate.
We can know that as definitely from Linux, for instance, so we check that the commits are
signed.
We do get log, dash, dash, show signature, and we see that we have a good signature from
Linux Torables, but it's not authenticated.
That's not so good.
Then we have a good signature for me, and it is authenticated.
But we want to check that they're from the expected certificates.
This is not from Linux's certificate.
It says Linux on it, but it's not Linux's certificate.
So how do we authenticate a project?
We have to create a list of all the contributors, and get all of their certificates.
That's on a small project, maybe okay, for a big project like the Linux kernel.
That's quite a lot of work.
We have to track when contributors join and leave the project, because here, we see on
the right, that Alice joins the project, she adds a commit, maybe she adds five, at some
point she leaves the project, she's no longer allowed, maybe she was kicked out, and then
she adds another commit.
The old ones, they're okay, presumably the maintainers have re-audited if they kicked
her out, and they decided that it was okay, but the new ones are not okay.
Now we have a temporal element as well.
This is getting really complicated, we need tooling.
The maintainers need tooling, and for the third parties, maintaining this database is just
completely impossible, because I use a lot of software.
There's no way that I can track all of the maintainers and all of the politics and everything.
I have to delegate this to the maintainers.
So I need to rely on as a third party, the maintainer, to somehow do something, to maintain
this database.
So, why do we want to do this?
We want, of course, to detect the unauthorized commits, as I said before, with the impersonation
thing, we have a malicious forge, we have a compromise forge of accounts, maybe there's
a machine in the middle, but we also want to detect the case when the forge or registry
gives the project to a new maintainer.
So it may be, and we saw, for instance, in the node world with the registries, that
they'll just randomly give a project, we'll take it away from one maintainer and give it
to another, or that happened in the Ruby space recently, and in the node space, there were
some abandoned projects and they just gave them to new maintainers, and maybe they were
malicious, and some of them actually were, and that was a big problem.
And I wanted to detect that.
If the forge goes ahead and does a rug pull, then I as a third party want to easily detect
that that happens.
OK, so we kind of see the problem, what is the solution?
Look like, well, we definitely need some clear semantics for assigning commits because
nobody really understands what's going on.
We need the project to maintain a siding policy, which evolves over time, and we want
our third parties to be able to rely on the maintainers of the projects to authenticate
the project.
And how do we do that?
Well, they're still a check-in-volved, it's just a smaller check.
At the time that we want to use the project, we do an audit.
We look at the code, does the pass the smell tests, we look to see who the maintainers of
the project are, are they trustworthy, do I know them, maybe not personally, but I've
heard of them, they have a reputation, I look online, OK, I'm happy, or maybe I'm a company,
and I actually pay some people to do an audit, I don't know.
But somehow you decide, OK, at this point in time, at this commit, I trust the project,
and then in the future, we're going to chain forward.
Now, the limitations of this is that since we're relying on the maintainers of the project
to maintain the database, if the maintainers are tricked, if there's some sort of social
engineering, then all bets are off, right, because the maintainer of the project is going
to add some g-chain to the list of authenticated commuters, and then they go ahead and
they add it, and I'm not going to detect that.
We can't detect social engineering, but we can detect the rug pull, we can detect impersonation,
and we can detect attacks on infrastructure.
All right, additional goals, we do not rely on authority.
That means that we want verification, not attestation.
Just because GitHub said it was so, does not mean that it is so.
Just because I use six or in Google says that this is a certificate that belongs to me,
does not mean it is so.
I want to verify this.
So Sequoia gets our tool.
It contains three parts.
We have a specification, you can see it over here.
It's not been certified by the ITF, but there is a long document described
all the semantics of somebody could come along and implement their own tool.
We have a configuration file, and I'm a whole bunch of tooling around it.
So the signing policy, the most important thing, the center of the how this works,
it's stored in the Git project itself, not separately in the exact same repository,
that means that evolves with the project, when Alice leaves the project,
the maintainer of the project, modifies this file and says Alice has left.
That means commits before, we can still authenticate commits after, Alice, no, rejected.
We have different capabilities.
We have users who are allowed to add commits.
We have users who are allowed to add tags, create a release, add remove other users,
and even audit commits, which is needed if somebody's certificate has been compromised,
then the maintainer needs to go back and check that the commits are okay.
And also market as search.
Okay.
So on the right-hand side, we see it, the policy file, it is a tumble file at the start,
we have the version, we have the list of the good commits, those that have been audited,
we don't have any compromised keys in this case.
And then we have two certificates here, one for Neil and one for Neil offline.
The Neil certificate is only allowed to add commits to the repository,
but the Neil offline certificate, because on my UB key,
that is allowed to do releases to add users and remove them.
So it's relatively straightforward, but the good news is the maintainer doesn't have to do it themselves,
or do it manually, there's a tool.
So if we want to add, for instance, Alice to the repository, we can run SQGIT policy authorized Alice.
We specify her certificate, and then we see here that Alice was audited, she was granted the
sign commit rights, and then this is her certificate.
And if we want to update it, because people change their certificates, they extend the expiration,
we can do SQGIT policy sync, it goes to the local certificate store that you have,
it goes to a bunch of different key stores, key servers, and checks for updates and integrates them.
And if we want to examine the policy, it's also relatively straightforward,
SQGIT policy described, and here we see all of the people that are allowed to do different things,
what their certificates are, and what their rights are.
Okay, so how do we authenticate commits? What does it mean for a commit to be authenticated?
And SQGIT, we say a commit is authenticated if at least one, not all, at least one,
of the parents say that the commit is acceptable.
So we have the current commit, I want you authenticated, I look at the parent commit,
I get the policy out of the parent commit, and I say does the policy say that this person
is allowed to make this change? And if it has multiple parents, for instance, with the merch
commit, then any of one of them can do it, any one of the parents. Okay, so that's how we authenticated commit,
but how do we authenticate a range of commits? Well, we need a path from A to B, so here we have a path
from the top to the bottom. There's a merch commit involved, only one of the branches of the merch
commit is completely authenticated, and so we have a path from the top to the bottom, and so we
consider this range of commits to be authenticated. Now, why don't we need both branches to be authenticated?
The answer is simple, the person who adds the merch commit has presumably reviewed the changes
in the unauthenticated paths, so there still needs to be the authenticated path for the merch commit,
but we can add things from other people. So how does it look? A quick example, here we have
GitLog graph on the left, and it shows that we have four commits, and on the right we use SQ GitLog
in order to check whether or not a range of commits is considered authenticated. So we have to
specify the starting commit, which is our trust root, that's the point where we audited the project,
and in this case we're going to use the first commit AAB50, and then we see that we check the three
commits that come afterwards, and we can see here in violet that Alice signed the most recent commit
and meal offline signed the other two, and that they were considered okay, there is a verified path
here from the trust root, and then SQ Git returns to zero. What happens if we can't verify
how does that look? Let's imagine that we have Bob come along, he adds a commit to the project,
so if you look here on the left, GitLog shows signature dash n2, we have a commit from Bob,
it is a good signature from Bob, we have the certificate locally, we authenticated it,
maybe we've been no Bob personally, but the maintainer of the project didn't say that Bob
is supposed to commit to the project, and SQ Git detects that, it says error this certificate, or
key is missing from the policy file, we're not able to verify this commit, there is no authenticated
path from the trust root to the head, Bob adds a commit, he is not authorized, rejected,
exit code 1. Okay, so what can we do if we want to merge commits from other people, right,
because when we have a free and open source project, we have the core team, but we also have external
people who come along, well the committer can re-sign Bob's commit, this preserves the
you know, I'm going to take two more minutes on this. Preserve the linear history, or we use
a merge commit, so Alice can go ahead and merge Bob's commit, and in this case we have to use
the dash n0 fast forward otherwise Git is so smart that it just says okay we're going to fast
forward it, so we look here on the left, we see we have a merge commit on top, and then on the
right we see here that SQKit correctly detects that the commit from Bob itself is not authenticated,
but that there is a path, and so we're able to authenticate the new head, which is the merge commit.
So more details, yes you can update your own expired certificate if you haven't committed to the
project for a while, we can recover from hard removal keys by using good listing, we can verify
tags and terables, that's specified in the document, but the implementation is incomplete,
and there's a lot more details in the manpages and documentation. What about forking a project,
we absolutely support that, basically the new maintainer is if it's a fork that's not authorized,
it's not going to appear in the file, but that's exactly the semantics that we want, right,
if somebody forks a project comes in and starts adding commits, I want to know about that, I want
SQKit to say, hey, this is not good. All right, how can you integrate it? SQKit, if using just a
get yourself, then you can use a hook, you can add it to your GitLab CI using this little snippet,
we have a container that has SQKit and does all the right things. If you're on GitHub, we have an action,
unfortunately GitHub destroy signatures on fast forward, so you also need to be extra careful
there, and we have a fast forward action that helps, and here you can see on GitHub, the output of SQKit,
it displays that the new commits are authenticated. So related work, I want to point out very quickly
that Ludovic Quote has had a talk here a couple of years ago about building a secure supply chain
for geeks, and he has a similar system to the one that I describe, the semantics are different,
it's not exactly the same thing, but I'm particularly grateful for the work that Ludovic has done,
and I encourage you to look there as well. And finally, signing commits is useful, we just need
better tooling, I believe that SQKit provides that tooling, and I hope that it's going to help
protect against the impersonations, detect unauthorized commits, and that we don't need to have the
forge as part of our trusted computing base. Thank you.
So I think we have time for some questions, maybe I can hijack this and have start with one,
get this shall-one based, is that the problem here? Is it a problem of the shall-one based?
Yeah, I have someone forges shall-one, identical shall-one commit, that the signatures will
apply to identical shall-one commit. That's a good question, but I'm not sure, but the answer
is definitely once we move to shot 256, then things will be looking better, and everybody is using
the shall-one CD implementation, so we're kind of protected anyways. But I think this would
depend basically on second-premage. So for arbitrary commit, you want another one that has the same
hash. It's like the one, I have one question, very short one. Yeah, when I do like
merit on a rebase is, can I sign like the rebase commits? Yeah, because there are different
authors in the rebase. Yeah, yeah. Yeah, the person who does the signature does not have to
actually match the author, so it's only looking at the signature.
Do you have any thoughts or plans about how or if this could integrate with signing releases
as well? Like, if could you use this to declare the policy this key has allowed to sign releases
and do software supply chain stuff like that? Yeah, absolutely. So the focus in this talk was on
the commits, but we also have support for authenticating tags and releases. That's primarily
in the spec. The implementation has not done the association between the policy and the
tarbles yet, but that's hopefully going to be something for the future.
Thank you very much. Thank you.