@@ -5,6 +5,7 @@ package asymkey
55
66import (
77 "context"
8+ "fmt"
89 "strings"
910
1011 asymkey_model "code.gitea.io/gitea/models/asymkey"
@@ -14,6 +15,7 @@ import (
1415 "code.gitea.io/gitea/modules/log"
1516 "code.gitea.io/gitea/modules/setting"
1617
18+ "github.com/42wim/sshsig"
1719 "github.com/ProtonMail/go-crypto/openpgp/packet"
1820)
1921
@@ -57,7 +59,7 @@ func ParseCommitWithSignatureCommitter(ctx context.Context, c *git.Commit, commi
5759
5860 // If this a SSH signature handle it differently
5961 if strings .HasPrefix (c .Signature .Signature , "-----BEGIN SSH SIGNATURE-----" ) {
60- return asymkey_model . ParseCommitWithSSHSignature (ctx , c , committer )
62+ return ParseCommitWithSSHSignature (ctx , c , committer )
6163 }
6264
6365 // Parsing signature
@@ -361,3 +363,65 @@ func VerifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, si
361363 }
362364 return nil
363365}
366+
367+ // ParseCommitWithSSHSignature check if signature is good against keystore.
368+ func ParseCommitWithSSHSignature (ctx context.Context , c * git.Commit , committer * user_model.User ) * asymkey_model.CommitVerification {
369+ // Now try to associate the signature with the committer, if present
370+ if committer .ID != 0 {
371+ keys , err := db .Find [asymkey_model.PublicKey ](ctx , asymkey_model.FindPublicKeyOptions {
372+ OwnerID : committer .ID ,
373+ NotKeytype : asymkey_model .KeyTypePrincipal ,
374+ })
375+ if err != nil { // Skipping failed to get ssh keys of user
376+ log .Error ("ListPublicKeys: %v" , err )
377+ return & asymkey_model.CommitVerification {
378+ CommittingUser : committer ,
379+ Verified : false ,
380+ Reason : "gpg.error.failed_retrieval_gpg_keys" ,
381+ }
382+ }
383+
384+ committerEmailAddresses , err := user_model .GetEmailAddresses (ctx , committer .ID )
385+ if err != nil {
386+ log .Error ("GetEmailAddresses: %v" , err )
387+ }
388+
389+ activated := false
390+ for _ , e := range committerEmailAddresses {
391+ if e .IsActivated && strings .EqualFold (e .Email , c .Committer .Email ) {
392+ activated = true
393+ break
394+ }
395+ }
396+
397+ for _ , k := range keys {
398+ if k .Verified && activated {
399+ commitVerification := verifySSHCommitVerification (c .Signature .Signature , c .Signature .Payload , k , committer , committer , c .Committer .Email )
400+ if commitVerification != nil {
401+ return commitVerification
402+ }
403+ }
404+ }
405+ }
406+
407+ return & asymkey_model.CommitVerification {
408+ CommittingUser : committer ,
409+ Verified : false ,
410+ Reason : asymkey_model .NoKeyFound ,
411+ }
412+ }
413+
414+ func verifySSHCommitVerification (sig , payload string , k * asymkey_model.PublicKey , committer , signer * user_model.User , email string ) * asymkey_model.CommitVerification {
415+ if err := sshsig .Verify (strings .NewReader (payload ), []byte (sig ), []byte (k .Content ), "git" ); err != nil {
416+ return nil
417+ }
418+
419+ return & asymkey_model.CommitVerification { // Everything is ok
420+ CommittingUser : committer ,
421+ Verified : true ,
422+ Reason : fmt .Sprintf ("%s / %s" , signer .Name , k .Fingerprint ),
423+ SigningUser : signer ,
424+ SigningSSHKey : k ,
425+ SigningEmail : email ,
426+ }
427+ }
0 commit comments