mirror of
https://codeberg.org/davrot/forgejo.git
synced 2025-05-16 02:00:02 +02:00
models/asymkey: Implement Tag verification
This is, in large part, a refactoring: we rename `CommitVerification` to `ObjectVerification`, and adjust `ParseObjectWithSignature` (previously `ParseCommitWithSignature`) to work on an object, rather than a commit. This in turn, lets us implement `ParseTagWithSignature` on top of it, so commit & tag signature verification will share most of the code. Work sponsored by @glts. Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
This commit is contained in:
parent
bc04183e47
commit
cd19564acc
6 changed files with 568 additions and 501 deletions
85
models/asymkey/ssh_key_object_verification.go
Normal file
85
models/asymkey/ssh_key_object_verification.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package asymkey
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/42wim/sshsig"
|
||||
)
|
||||
|
||||
// ParseObjectWithSSHSignature check if signature is good against keystore.
|
||||
func ParseObjectWithSSHSignature(ctx context.Context, c *GitObject, committer *user_model.User) *ObjectVerification {
|
||||
// Now try to associate the signature with the committer, if present
|
||||
if committer.ID != 0 {
|
||||
keys, err := db.Find[PublicKey](ctx, FindPublicKeyOptions{
|
||||
OwnerID: committer.ID,
|
||||
NotKeytype: KeyTypePrincipal,
|
||||
})
|
||||
if err != nil { // Skipping failed to get ssh keys of user
|
||||
log.Error("ListPublicKeys: %v", err)
|
||||
return &ObjectVerification{
|
||||
CommittingUser: committer,
|
||||
Verified: false,
|
||||
Reason: "gpg.error.failed_retrieval_gpg_keys",
|
||||
}
|
||||
}
|
||||
|
||||
committerEmailAddresses, err := user_model.GetEmailAddresses(ctx, committer.ID)
|
||||
if err != nil {
|
||||
log.Error("GetEmailAddresses: %v", err)
|
||||
}
|
||||
|
||||
// Add the noreply email address as verified address.
|
||||
committerEmailAddresses = append(committerEmailAddresses, &user_model.EmailAddress{
|
||||
IsActivated: true,
|
||||
Email: committer.GetPlaceholderEmail(),
|
||||
})
|
||||
|
||||
activated := false
|
||||
for _, e := range committerEmailAddresses {
|
||||
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
|
||||
activated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, k := range keys {
|
||||
if k.Verified && activated {
|
||||
commitVerification := verifySSHObjectVerification(c.Signature.Signature, c.Signature.Payload, k, committer, committer, c.Committer.Email)
|
||||
if commitVerification != nil {
|
||||
return commitVerification
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &ObjectVerification{
|
||||
CommittingUser: committer,
|
||||
Verified: false,
|
||||
Reason: NoKeyFound,
|
||||
}
|
||||
}
|
||||
|
||||
func verifySSHObjectVerification(sig, payload string, k *PublicKey, committer, signer *user_model.User, email string) *ObjectVerification {
|
||||
if err := sshsig.Verify(bytes.NewBuffer([]byte(payload)), []byte(sig), []byte(k.Content), "git"); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ObjectVerification{ // Everything is ok
|
||||
CommittingUser: committer,
|
||||
Verified: true,
|
||||
Reason: fmt.Sprintf("%s / %s", signer.Name, k.Fingerprint),
|
||||
SigningUser: signer,
|
||||
SigningSSHKey: k,
|
||||
SigningEmail: email,
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue