Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ssh commit signing #17743

Merged
merged 27 commits into from
Dec 19, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8d38285
Add support for ssh commit signing
42wim Nov 21, 2021
9b1182b
Split out ssh verification to separate file
42wim Nov 21, 2021
9f113c3
Show ssh key fingerprint on commit page
42wim Nov 21, 2021
af5fc14
Update sshsig lib
42wim Nov 21, 2021
7b6b1a1
Make sure we verify against correct namespace
42wim Nov 21, 2021
741ad05
Add ssh public key verification via ssh signatures
42wim Nov 21, 2021
bea996d
Remove some gpg references and make verify key optional
42wim Nov 21, 2021
5439269
Fix spaces indentation
42wim Nov 21, 2021
2d0bdf0
Update options/locale/locale_en-US.ini
42wim Nov 22, 2021
fd91370
Update templates/user/settings/keys_ssh.tmpl
42wim Nov 22, 2021
543c972
Update options/locale/locale_en-US.ini
42wim Nov 22, 2021
4ab202f
Update options/locale/locale_en-US.ini
42wim Nov 22, 2021
1172df7
Update models/ssh_key_commit_verification.go
42wim Nov 22, 2021
496b0aa
Reword ssh/gpg_key_success message
42wim Nov 22, 2021
d216536
Merge branch 'main' into ssh-sign
42wim Nov 22, 2021
b02effc
Change Badsignature to NoKeyFound
42wim Nov 22, 2021
378f119
Merge branch 'main' into ssh-sign
42wim Nov 27, 2021
670cc92
Add sign/verify tests
42wim Dec 1, 2021
2ccc73d
Merge branch 'main' into ssh-sign
42wim Dec 1, 2021
fcf0178
Fix upstream api changes to user_model User
42wim Dec 1, 2021
aa5074b
Merge branch 'main' into ssh-sign
wxiaoguang Dec 3, 2021
3b406a3
Match exact on SSH signature
42wim Dec 3, 2021
bf66261
Merge branch 'main' into ssh-sign
42wim Dec 12, 2021
72a8d09
Fix code review remarks
42wim Dec 12, 2021
4b22267
Merge branch 'main' into ssh-sign
42wim Dec 19, 2021
882a980
Merge branch 'main' into ssh-sign
lunny Dec 19, 2021
9da693f
Merge branch 'main' into ssh-sign
techknowlogick Dec 19, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5
gitea.com/go-chi/session v0.0.0-20211013065435-7d334f340c09
gitea.com/lunny/levelqueue v0.4.1
github.com/42wim/sshsig v0.0.0-20211120223956-aea46ba47435
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/NYTimes/gziphandler v1.1.1
github.com/ProtonMail/go-crypto v0.0.0-20210705153151-cc34b1f6908b // indirect
Expand Down Expand Up @@ -122,8 +123,8 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.19.0 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf
golang.org/x/text v0.3.7
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ gitea.com/lunny/levelqueue v0.4.1 h1:RZ+AFx5gBsZuyqCvofhAkPQ9uaVDPJnsULoJZIYaJNw
gitea.com/lunny/levelqueue v0.4.1/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
github.com/42wim/sshsig v0.0.0-20211120223956-aea46ba47435 h1:lvJzGuCfsbYvu3+GpNUvOVQVK3TjvQ1S4ej8IRmKU1E=
github.com/42wim/sshsig v0.0.0-20211120223956-aea46ba47435/go.mod h1:TbzEKt2Ju8MHx8VCurIA4YsYPz/OsEBN6wq1u+ckV68=
github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U=
github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
Expand Down Expand Up @@ -1263,6 +1265,8 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -1357,6 +1361,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down
83 changes: 83 additions & 0 deletions models/gpg_key_commit_verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package models

import (
"bytes"
"fmt"
"hash"
"strings"
Expand All @@ -15,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"

"github.com/42wim/sshsig"
"github.com/keybase/go-crypto/openpgp/packet"
)

Expand Down Expand Up @@ -48,6 +50,7 @@ type CommitVerification struct {
CommittingUser *User
SigningEmail string
SigningKey *GPGKey
SigningSSHKey *PublicKey
TrustStatus string
}

Expand Down Expand Up @@ -86,6 +89,67 @@ func ParseCommitsWithSignature(oldCommits []*UserCommit, repository *Repository)
return newCommits
}

// ParseCommitWithSignature check if signature is good against keystore.
func ParseCommitWithSSHSignature(c *git.Commit, committer *User) *CommitVerification {
// Now try to associate the signature with the committer, if present
if committer.ID != 0 {
keys, err := ListPublicKeys(committer.ID, db.ListOptions{})
if err != nil { // Skipping failed to get gpg keys of user
log.Error("ListPublicKeys: %v", err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.failed_retrieval_gpg_keys",
}
}

committerEmailAddresses, _ := user_model.GetEmailAddresses(committer.ID)
activated := false
for _, e := range committerEmailAddresses {
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
activated = true
break
}
}

for _, k := range keys {
// Pre-check (& optimization) that emails attached to key can be attached to the committer email and can validate
canValidate := false
email := ""
// if k.Verified && activated {
if activated {
canValidate = true
email = c.Committer.Email
}
/*
if !canValidate {
for _, e := range k.Emails {
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
canValidate = true
email = e.Email
break
}
}
}
*/
if !canValidate {
continue // Skip this key
}

commitVerification := verifySSHCommitVerification(c.Signature.Signature, c.Signature.Payload, k, committer, committer, email)
if commitVerification != nil {
return commitVerification
}
}
}

return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.verification_failed",
}
}

// ParseCommitWithSignature check if signature is good against keystore.
func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
var committer *User
Expand Down Expand Up @@ -121,6 +185,10 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
}
}

if strings.Contains(c.Signature.Signature, "SSH") {
return ParseCommitWithSSHSignature(c, committer)
}

// Parsing signature
sig, err := extractSignature(c.Signature.Signature)
if err != nil { // Skipping failed to extract sign
Expand Down Expand Up @@ -357,6 +425,21 @@ func hashAndVerifyWithSubKeys(sig *packet.Signature, payload string, k *GPGKey)
return nil, nil
}

func verifySSHCommitVerification(sig, payload string, k *PublicKey, committer, signer *User, email string) *CommitVerification {
if err := sshsig.Verify(bytes.NewBuffer([]byte(payload)), []byte(sig), []byte(k.Content)); err != nil {
return &CommitVerification{ // Everything is ok
CommittingUser: committer,
Verified: true,
Reason: fmt.Sprintf("%s / %s", signer.Name, k.Fingerprint),
SigningUser: signer,
SigningSSHKey: k,
SigningEmail: email,
}
}

return nil
}

func hashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload string, k *GPGKey, committer, signer *User, email string) *CommitVerification {
key, err := hashAndVerifyWithSubKeys(sig, payload, k)
if err != nil { // Skipping failed to generate hash
Expand Down
201 changes: 201 additions & 0 deletions vendor/github.com/42wim/sshsig/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading