Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ssh_key_fingerprint.go 3.1KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package asymkey
  4. import (
  5. "context"
  6. "fmt"
  7. "strings"
  8. "code.gitea.io/gitea/models/db"
  9. "code.gitea.io/gitea/modules/log"
  10. "code.gitea.io/gitea/modules/process"
  11. "code.gitea.io/gitea/modules/setting"
  12. "code.gitea.io/gitea/modules/util"
  13. "golang.org/x/crypto/ssh"
  14. "xorm.io/builder"
  15. )
  16. // ___________.__ .__ __
  17. // \_ _____/|__| ____ ____ ________________________|__| _____/ |_
  18. // | __) | |/ \ / ___\_/ __ \_ __ \____ \_ __ \ |/ \ __\
  19. // | \ | | | \/ /_/ > ___/| | \/ |_> > | \/ | | \ |
  20. // \___ / |__|___| /\___ / \___ >__| | __/|__| |__|___| /__|
  21. // \/ \//_____/ \/ |__| \/
  22. //
  23. // This file contains functions for fingerprinting SSH keys
  24. //
  25. // The database is used in checkKeyFingerprint however most of these functions probably belong in a module
  26. // checkKeyFingerprint only checks if key fingerprint has been used as public key,
  27. // it is OK to use same key as deploy key for multiple repositories/users.
  28. func checkKeyFingerprint(ctx context.Context, fingerprint string) error {
  29. has, err := db.Exist[PublicKey](ctx, builder.Eq{"fingerprint": fingerprint})
  30. if err != nil {
  31. return err
  32. } else if has {
  33. return ErrKeyAlreadyExist{0, fingerprint, ""}
  34. }
  35. return nil
  36. }
  37. func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) {
  38. // Calculate fingerprint.
  39. tmpPath, err := writeTmpKeyFile(publicKeyContent)
  40. if err != nil {
  41. return "", err
  42. }
  43. defer func() {
  44. if err := util.Remove(tmpPath); err != nil {
  45. log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpPath, err)
  46. }
  47. }()
  48. stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
  49. if err != nil {
  50. if strings.Contains(stderr, "is not a public key file") {
  51. return "", ErrKeyUnableVerify{stderr}
  52. }
  53. return "", util.NewInvalidArgumentErrorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
  54. } else if len(stdout) < 2 {
  55. return "", util.NewInvalidArgumentErrorf("not enough output for calculating fingerprint: %s", stdout)
  56. }
  57. return strings.Split(stdout, " ")[1], nil
  58. }
  59. func calcFingerprintNative(publicKeyContent string) (string, error) {
  60. // Calculate fingerprint.
  61. pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent))
  62. if err != nil {
  63. return "", err
  64. }
  65. return ssh.FingerprintSHA256(pk), nil
  66. }
  67. // CalcFingerprint calculate public key's fingerprint
  68. func CalcFingerprint(publicKeyContent string) (string, error) {
  69. // Call the method based on configuration
  70. var (
  71. fnName, fp string
  72. err error
  73. )
  74. if len(setting.SSH.KeygenPath) == 0 {
  75. fnName = "calcFingerprintNative"
  76. fp, err = calcFingerprintNative(publicKeyContent)
  77. } else {
  78. fnName = "calcFingerprintSSHKeygen"
  79. fp, err = calcFingerprintSSHKeygen(publicKeyContent)
  80. }
  81. if err != nil {
  82. if IsErrKeyUnableVerify(err) {
  83. log.Info("%s", publicKeyContent)
  84. return "", err
  85. }
  86. return "", fmt.Errorf("%s: %w", fnName, err)
  87. }
  88. return fp, nil
  89. }