code.gitea.io/gitea@v1.22.3/models/asymkey/ssh_key_commit_verification.go (about) 1 // Copyright 2021 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package asymkey 5 6 import ( 7 "bytes" 8 "context" 9 "fmt" 10 "strings" 11 12 "code.gitea.io/gitea/models/db" 13 user_model "code.gitea.io/gitea/models/user" 14 "code.gitea.io/gitea/modules/git" 15 "code.gitea.io/gitea/modules/log" 16 17 "github.com/42wim/sshsig" 18 ) 19 20 // ParseCommitWithSSHSignature check if signature is good against keystore. 21 func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committer *user_model.User) *CommitVerification { 22 // Now try to associate the signature with the committer, if present 23 if committer.ID != 0 { 24 keys, err := db.Find[PublicKey](ctx, FindPublicKeyOptions{ 25 OwnerID: committer.ID, 26 NotKeytype: KeyTypePrincipal, 27 }) 28 if err != nil { // Skipping failed to get ssh keys of user 29 log.Error("ListPublicKeys: %v", err) 30 return &CommitVerification{ 31 CommittingUser: committer, 32 Verified: false, 33 Reason: "gpg.error.failed_retrieval_gpg_keys", 34 } 35 } 36 37 committerEmailAddresses, err := user_model.GetEmailAddresses(ctx, committer.ID) 38 if err != nil { 39 log.Error("GetEmailAddresses: %v", err) 40 } 41 42 activated := false 43 for _, e := range committerEmailAddresses { 44 if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) { 45 activated = true 46 break 47 } 48 } 49 50 for _, k := range keys { 51 if k.Verified && activated { 52 commitVerification := verifySSHCommitVerification(c.Signature.Signature, c.Signature.Payload, k, committer, committer, c.Committer.Email) 53 if commitVerification != nil { 54 return commitVerification 55 } 56 } 57 } 58 } 59 60 return &CommitVerification{ 61 CommittingUser: committer, 62 Verified: false, 63 Reason: NoKeyFound, 64 } 65 } 66 67 func verifySSHCommitVerification(sig, payload string, k *PublicKey, committer, signer *user_model.User, email string) *CommitVerification { 68 if err := sshsig.Verify(bytes.NewBuffer([]byte(payload)), []byte(sig), []byte(k.Content), "git"); err != nil { 69 return nil 70 } 71 72 return &CommitVerification{ // Everything is ok 73 CommittingUser: committer, 74 Verified: true, 75 Reason: fmt.Sprintf("%s / %s", signer.Name, k.Fingerprint), 76 SigningUser: signer, 77 SigningSSHKey: k, 78 SigningEmail: email, 79 } 80 }