diff options
author | Daniel Baumann <daniel@debian.org> | 2024-10-18 20:33:49 +0200 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-12-12 23:57:56 +0100 |
commit | e68b9d00a6e05b3a941f63ffb696f91e554ac5ec (patch) | |
tree | 97775d6c13b0f416af55314eb6a89ef792474615 /models/asymkey/ssh_key_fingerprint.go | |
parent | Initial commit. (diff) | |
download | forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.tar.xz forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.zip |
Adding upstream version 9.0.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'models/asymkey/ssh_key_fingerprint.go')
-rw-r--r-- | models/asymkey/ssh_key_fingerprint.go | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/models/asymkey/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go new file mode 100644 index 0000000..1ed3b5d --- /dev/null +++ b/models/asymkey/ssh_key_fingerprint.go @@ -0,0 +1,89 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package asymkey + +import ( + "context" + "fmt" + "strings" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" + + "golang.org/x/crypto/ssh" + "xorm.io/builder" +) + +// ___________.__ .__ __ +// \_ _____/|__| ____ ____ ________________________|__| _____/ |_ +// | __) | |/ \ / ___\_/ __ \_ __ \____ \_ __ \ |/ \ __\ +// | \ | | | \/ /_/ > ___/| | \/ |_> > | \/ | | \ | +// \___ / |__|___| /\___ / \___ >__| | __/|__| |__|___| /__| +// \/ \//_____/ \/ |__| \/ +// +// This file contains functions for fingerprinting SSH keys +// +// The database is used in checkKeyFingerprint however most of these functions probably belong in a module + +// checkKeyFingerprint only checks if key fingerprint has been used as public key, +// it is OK to use same key as deploy key for multiple repositories/users. +func checkKeyFingerprint(ctx context.Context, fingerprint string) error { + has, err := db.Exist[PublicKey](ctx, builder.Eq{"fingerprint": fingerprint}) + if err != nil { + return err + } else if has { + return ErrKeyAlreadyExist{0, fingerprint, ""} + } + return nil +} + +func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) { + // Calculate fingerprint. + tmpPath, err := writeTmpKeyFile(publicKeyContent) + if err != nil { + return "", err + } + defer func() { + if err := util.Remove(tmpPath); err != nil { + log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpPath, err) + } + }() + stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath) + if err != nil { + if strings.Contains(stderr, "is not a public key file") { + return "", ErrKeyUnableVerify{stderr} + } + return "", util.NewInvalidArgumentErrorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr) + } else if len(stdout) < 2 { + return "", util.NewInvalidArgumentErrorf("not enough output for calculating fingerprint: %s", stdout) + } + return strings.Split(stdout, " ")[1], nil +} + +func calcFingerprintNative(publicKeyContent string) (string, error) { + // Calculate fingerprint. + pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent)) + if err != nil { + return "", err + } + return ssh.FingerprintSHA256(pk), nil +} + +// CalcFingerprint calculate public key's fingerprint +func CalcFingerprint(publicKeyContent string) (string, error) { + // Call the method based on configuration + useNative := setting.SSH.KeygenPath == "" + calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen) + fp, err := calcFn(publicKeyContent) + if err != nil { + if IsErrKeyUnableVerify(err) { + return "", err + } + return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err) + } + return fp, nil +} |