From 1ef5496055c216d51f6ae0780fc72315c6ee478d Mon Sep 17 00:00:00 2001 From: 0ko <0ko@noreply.codeberg.org> Date: Wed, 17 Dec 2025 17:01:14 +0100 Subject: [PATCH] feat: use AppDomain for key verification (#10429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #10416 Followup to a hardcoded string in [gitea#17743](https://github.com/go-gitea/gitea/pull/17743) * instead of using a hardcoded namespace, use the configured application domain * `ssh-keygen` refuses to work with empty namespace, but `Domain` falls back to `localhost`: https://codeberg.org/forgejo/forgejo/src/commit/95dca7ff57955f5a08e656caf8ceb61c88201ff8/modules/setting/server.go#L192 * since `VerifySSHKey` verifies the namespace, I think that using a mostly-unique string instead of a hardcoded one doesn't hurt. Here's what `man ssh-keygen` says on the topic: > An additional signature namespace, used to prevent signature confusion across different domains of use (e.g. file signing vs email signing) must be provided via the -n flag. Namespaces are arbitrary strings, and may include: “file” for file signing, “email” for email signing. For custom uses, it is recommended to use names following a NAMESPACE@YOUR.DOMAIN pattern to generate unambiguous namespaces. ## Testing There's a test `TestFromOpenSSH` but it uses a hardcoded default namespace `file`: https://codeberg.org/forgejo/forgejo/src/commit/95dca7ff57955f5a08e656caf8ceb61c88201ff8/models/asymkey/ssh_key_test.go#L334 Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10429 Reviewed-by: Beowulf Reviewed-by: Gusted Co-authored-by: 0ko <0ko@noreply.codeberg.org> Co-committed-by: 0ko <0ko@noreply.codeberg.org> --- models/asymkey/ssh_key_verify.go | 5 +++-- templates/user/settings/keys_ssh.tmpl | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go index 5dd26ccc9a..6ffb6763f6 100644 --- a/models/asymkey/ssh_key_verify.go +++ b/models/asymkey/ssh_key_verify.go @@ -9,6 +9,7 @@ import ( "forgejo.org/models/db" "forgejo.org/modules/log" + "forgejo.org/modules/setting" "github.com/42wim/sshsig" ) @@ -30,11 +31,11 @@ func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signat return "", ErrKeyNotExist{} } - err = sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea") + err = sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), setting.Domain) if err != nil { // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command // see https://github.com/PowerShell/PowerShell/issues/5974 - if sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") != nil { + if sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), setting.Domain) != nil { log.Error("Unable to validate token signature. Error: %v", err) return "", ErrSSHInvalidTokenSignature{ Fingerprint: key.Fingerprint, diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index d4931d62c1..57f4ef4010 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -78,19 +78,19 @@

{{ctx.Locale.Tr "settings.ssh_token_help"}}

-
echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n gitea -f ~/.ssh/id_ed25519 # or the path to the private key if it is different.
+
echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n {{AppDomain}} -f ~/.ssh/id_ed25519 # or the path to the private key if it is different.

{{ctx.Locale.Tr "settings.ssh_token_help_ssh_agent"}}

-
bash -c "echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n gitea -f <(echo '{{.OmitEmail}}')"
+
bash -c "echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n {{AppDomain}} -f <(echo '{{.OmitEmail}}')"

Windows PowerShell -
cmd /c "<NUL set /p=`"{{$.TokenToSign}}`"| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey"
+
cmd /c "<NUL set /p=`"{{$.TokenToSign}}`"| ssh-keygen -Y sign -n {{AppDomain}} -f /path_to_PrivateKey_or_RelatedPublicKey"

Windows CMD -
<NUL set /p="{{$.TokenToSign}}"| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey
+
<NUL set /p="{{$.TokenToSign}}"| ssh-keygen -Y sign -n {{AppDomain}} -f /path_to_PrivateKey_or_RelatedPublicKey