GPG Signature never verifies if signing is done on Windows #14542

Open
opened 2025-11-02 11:15:43 -06:00 by GiteaMirror · 14 comments
Owner

Originally created by @ieris19 on GitHub (Jun 3, 2025).

Description

I have attempted several times to set up Git commit signing in both Linux and Windows. Linux is always a breeze, generate a key, setup git, commit with signature, passphrase and off-you-go. With Windows, it's always MASSIVE pain in the ass every time, and its never worked.

Never knew why either, until now. I have recently realized that my GPG signatures are different for the same content depending on the OS, which is a problem, because I believe that is the reason my git signatures work fine on Linux, but never on Windows, is because the servers are running Linux and are probably expecting the signature to be the same as the one it generates in Linux.

I am currently running Windows 11 and openSUSE Tumbleweed within WSL, but I have also verified with my Gitea server running Fedora. For the first two I am running gpg 2.5.6 with libgcrypt 1.11.1, Fedora is a bit behind at gpg 2.4.7 with libgcrypt 1.11.0-unknown as reported by the command:

$ gpg --version

I have followed GitHub's guide on how to generate a GPG key, using my Windows machine. Afterwards, I followed Red Hat's guide to migrate these keys onto other machines, in order to have the exact same key in every computer.

Uploading the key to Gitea promptly asks for confirmation, which is where the issue arises. Gitea offers a token and asks for a signature.

echo "[token]" | gpg -a --default-key [REDACTED] --detach-sig

Pasting this command into Windows, generates a signature that Gitea refuses with the following message:

The provided GPG key, signature and token do not match or token is out-of-date.

This has all been done on Windows so far, when I paste the command into either Linux environment that I imported the keys to, both times, the verification is simply accepted.

Unsurprisingly, committing from Windows doesn't verify the commits either

Gitea Version

1.23.7

Can you reproduce the bug on the Gitea demo site?

Yes

Git Version

git version 2.49.0

Operating System

Fedora Linux 42 (Workstation Edition)

How are you running Gitea?

I am running Gitea on bare metal from the executable provided at https://dl.gitea.com/gitea/
To be precise, https://dl.gitea.com/gitea/1.23.7/gitea-1.23.7-linux-amd64

I can also replicate the issue on https://demo.gitea.com

Database

SQLite

Originally created by @ieris19 on GitHub (Jun 3, 2025). ### Description I have attempted several times to set up Git commit signing in both Linux and Windows. Linux is always a breeze, generate a key, setup git, commit with signature, passphrase and off-you-go. With Windows, it's always MASSIVE pain in the ass every time, and its never worked. Never knew why either, until now. I have recently realized that my GPG signatures are different for the same content depending on the OS, which is a problem, because I believe that is the reason my git signatures work fine on Linux, but never on Windows, is because the servers are running Linux and are probably expecting the signature to be the same as the one it generates in Linux. I am currently running Windows 11 and openSUSE Tumbleweed within WSL, but I have also verified with my Gitea server running Fedora. For the first two I am running gpg 2.5.6 with libgcrypt 1.11.1, Fedora is a bit behind at gpg 2.4.7 with libgcrypt 1.11.0-unknown as reported by the command: ``` $ gpg --version ``` I have followed [GitHub's guide](http://docs.github.com/en/authentication/managing-commit-signature-verification/generating-a-new-gpg-key) on how to generate a GPG key, using my Windows machine. Afterwards, I followed [Red Hat's guide](https://access.redhat.com/solutions/2115511) to migrate these keys onto other machines, in order to have the exact same key in every computer. Uploading the key to Gitea promptly asks for confirmation, which is where the issue arises. Gitea offers a token and asks for a signature. ``` echo "[token]" | gpg -a --default-key [REDACTED] --detach-sig ``` Pasting this command into Windows, generates a signature that Gitea refuses with the following message: > The provided GPG key, signature and token do not match or token is out-of-date. This has all been done on Windows so far, when I paste the command into either Linux environment that I imported the keys to, both times, the verification is simply accepted. Unsurprisingly, committing from Windows doesn't verify the commits either ### Gitea Version 1.23.7 ### Can you reproduce the bug on the Gitea demo site? Yes ### Git Version git version 2.49.0 ### Operating System Fedora Linux 42 (Workstation Edition) ### How are you running Gitea? I am running Gitea on bare metal from the executable provided at https://dl.gitea.com/gitea/ To be precise, https://dl.gitea.com/gitea/1.23.7/gitea-1.23.7-linux-amd64 I can also replicate the issue on https://demo.gitea.com ### Database SQLite
GiteaMirror added the type/bug label 2025-11-02 11:15:43 -06:00
Author
Owner

@levicki commented on GitHub (Jun 15, 2025):

The problem is that the suggested signing command which works for Linux:

echo "<token>" | gpg ...

Results in <token>\n being sent to gpg for signing.

As you might have guessed, echo command under Windows not only keeps the quotes, but also replaces \n with \r\n resulting in the string "<token>\r\n" which doesn't match what Gitea expects to be signed.

Aggravating the problem is the short token validity time which makes it hard if not impossible to manually prepare the correct token string.

Proper fix would be not quoting the token in the command example, and not including OS-specific line ending in the verification string to begin with.

@levicki commented on GitHub (Jun 15, 2025): The problem is that the suggested signing command which works for Linux: ``` echo "<token>" | gpg ... ``` Results in `<token>\n` being sent to `gpg` for signing. As you might have guessed, `echo` command under Windows **not only keeps the quotes**, but also replaces `\n` with `\r\n` resulting in the string `"<token>\r\n"` which doesn't match what Gitea expects to be signed. Aggravating the problem is the short token validity time which makes it hard if not impossible to manually prepare the correct token string. Proper fix would be not quoting the token in the command example, and not including OS-specific line ending in the verification string to begin with.
Author
Owner

@ieris19 commented on GitHub (Jun 16, 2025):

Do you think then this issue runs deeper into Git for Windows as well? Even signing the commits through git directly never really worked on Gitea or Github for me, but that could also just be an issue with my setup. I have never managed to get git commit signing setup on Windows but it's always been dead simple on Linux.

My Windows machine is broken right now, so I can't quite test this, but I should have it back next week to further research the situation.

@ieris19 commented on GitHub (Jun 16, 2025): Do you think then this issue runs deeper into Git for Windows as well? Even signing the commits through git directly never really worked on Gitea or Github for me, but that could also just be an issue with my setup. I have never managed to get git commit signing setup on Windows but it's always been dead simple on Linux. My Windows machine is broken right now, so I can't quite test this, but I should have it back next week to further research the situation.
Author
Owner

@levicki commented on GitHub (Jun 16, 2025):

Do you think then this issue runs deeper into Git for Windows as well?

No, I have a working setup. I only discovered this problem as I had to reimport the keys since I lost the old ones to reinstall.

If you want to sign by default, install gpg4win (you only need Kleopatra checked from optional) and in your .gitconfig put:

[gpg]
	program = C:\\Program Files (x86)\\GnuPG\\bin\\gpg.exe
[commit]
	gpgsign = true
[tag]
	gpgSign = false

Tag bit is optional (I don't want signed tags since they require message).

@levicki commented on GitHub (Jun 16, 2025): > Do you think then this issue runs deeper into Git for Windows as well? No, I have a working setup. I only discovered this problem as I had to reimport the keys since I lost the old ones to reinstall. If you want to sign by default, install gpg4win (you only need Kleopatra checked from optional) and in your `.gitconfig` put: ``` [gpg] program = C:\\Program Files (x86)\\GnuPG\\bin\\gpg.exe [commit] gpgsign = true [tag] gpgSign = false ``` Tag bit is optional (I don't want signed tags since they require message).
Author
Owner

@GiteaBot commented on GitHub (Jul 17, 2025):

We close issues that need feedback from the author if there were no new comments for a month. 🍵

@GiteaBot commented on GitHub (Jul 17, 2025): We close issues that need feedback from the author if there were no new comments for a month. :tea:
Author
Owner

@levicki commented on GitHub (Jul 17, 2025):

We close issues that need feedback from the author if there were no new comments for a month. 🍵

@lunny Why is this still tagged as needs-feedback when all feedback necessary to reproduce and fix the reported issue was provided by me?

@levicki commented on GitHub (Jul 17, 2025): > We close issues that need feedback from the author if there were no new comments for a month. 🍵 @lunny Why is this still tagged as `needs-feedback` when all feedback necessary to reproduce and fix the reported issue was [provided by me](https://github.com/go-gitea/gitea/issues/34595#issuecomment-2973865796)?
Author
Owner

@ieris19 commented on GitHub (Jul 17, 2025):

Unfortunately, my Windows machine is still out of commission (the wonders of RMA repairs), but I believe something should still be done about this, at the very least as you @levicki said:

Proper fix would be not quoting the token in the command example, and not including OS-specific line ending in the verification string to begin with.

I can probably locate the relevant code and submit a pull request if it would be welcome, but I would need to get my Windows machine back before I can test it and submit a better cross-platform example command

@ieris19 commented on GitHub (Jul 17, 2025): Unfortunately, my Windows machine is still out of commission (the wonders of RMA repairs), but I believe something should still be done about this, at the very least as you @levicki said: > Proper fix would be not quoting the token in the command example, and not including OS-specific line ending in the verification string to begin with. I can probably locate the relevant code and submit a pull request if it would be welcome, but I would need to get my Windows machine back before I can test it and submit a better cross-platform example command
Author
Owner

@levicki commented on GitHub (Jul 18, 2025):

... a better cross-platform example command

That one is going to be a challenge on Windows. I was looking for a way and didn't find anything reliable, not to mention that some commands even output Unicode (UCS-2).

Ideal solution for users would be if Gitea had a small helper executable that registers as a protocol handler (for example gitea:) so when you click a link which looks like gitea://sign-challenge?key_id=fedbca&token=123abc browser launches the protocol handler with key id and challenge token as parameters which in turn talks to gpg-agent and prompts user to sign it using that key_id and then posts the signature back to your local Gitea instance for validation.

I do not have a slightest idea how to write cross-platform protocol handler though, and I somehow doubt the fine people who work on Gitea would expend the time to do this just to fix an occasional annoyance for a handful of Windows users they might have.

EDIT:

There's perhaps an easier option — writing a browser extension which uses Native Messaging to talk to gpg-agent.

It is cross-platform, user is already in the browser, and it would require minimal change on the Gitea server end to work.

@levicki commented on GitHub (Jul 18, 2025): > ... a better cross-platform example command That one is going to be a challenge on Windows. I was looking for a way and didn't find anything reliable, not to mention that some commands even output Unicode (UCS-2). Ideal solution for users would be if Gitea had a small helper executable that registers as a protocol handler (for example `gitea:`) so when you click a link which looks like `gitea://sign-challenge?key_id=fedbca&token=123abc` browser launches the protocol handler with key id and challenge token as parameters which in turn talks to `gpg-agent` and prompts user to sign it using that key_id and then posts the signature back to your local Gitea instance for validation. I do not have a slightest idea how to write cross-platform protocol handler though, and I somehow doubt the fine people who work on Gitea would expend the time to do this just to fix an occasional annoyance for a handful of Windows users they might have. **EDIT:** There's perhaps an easier option &mdash; writing a browser extension which uses Native Messaging to talk to `gpg-agent`. It is cross-platform, user is already in the browser, and it would require minimal change on the Gitea server end to work.
Author
Owner

@levicki commented on GitHub (Jul 18, 2025):

Another option would be a signing helper console app, here's a minimal working code example in .Net 8.0 (note that not all possible error conditions are handled!):


namespace GiteaGPGSigner
{
	using System.Diagnostics;
	using System.Net;
	using System.Text;
	using System.Text.Json;
	using System.Text.Json.Serialization;

	internal class SignRequest
	{
		[JsonPropertyName("key_id")]
		public string KeyID { get; set; }
		[JsonPropertyName("nonce")]
		public string Nonce { get; set; }
	}

	internal class Program
	{
		static HttpListener m_Listener;

		static async Task Main()
		{
			m_Listener = new HttpListener();
			m_Listener.Prefixes.Add("http://localhost:5000/");
			m_Listener.Start();
			Console.WriteLine("Gitea GPG signing server running on http://localhost:5000/");

			while (true) {
				var ctx = await m_Listener.GetContextAsync();
				_ = Task.Run(() => HandleRequest(ctx));
			}
		}

		static void HandleRequest(HttpListenerContext ctx)
		{
			if (ctx.Request.HttpMethod != "POST") {
				ctx.Response.StatusCode = 405;
				ctx.Response.Close();
				return;
			}

			try {
				using var reader = new System.IO.StreamReader(ctx.Request.InputStream, ctx.Request.ContentEncoding);
				var json = reader.ReadToEnd();
				var req = JsonSerializer.Deserialize<SignRequest>(json);

				if (req == null || string.IsNullOrWhiteSpace(req.KeyID) || string.IsNullOrWhiteSpace(req.Nonce)) {
					ctx.Response.StatusCode = 400;
					return;
				}

				string signature = SignChallenge(req.KeyID, req.Nonce);

				byte[] buffer = Encoding.UTF8.GetBytes(signature);
				ctx.Response.ContentType = "text/plain";
				ctx.Response.ContentLength64 = buffer.Length;
				ctx.Response.OutputStream.Write(buffer, 0, buffer.Length);
			} catch (Exception ex) {
				ctx.Response.StatusCode = 500;
			} finally {
				ctx.Response.Close();
			}
		}

		static string SignChallenge(string KeyID, string Nonce)
		{
			var psi = new ProcessStartInfo
			{
				FileName = "gpg",
				Arguments = $"--clearsign --local-user {KeyID}",
				RedirectStandardInput = true,
				RedirectStandardOutput = true,
				UseShellExecute = false,
				CreateNoWindow = false
			};

			using var process = Process.Start(psi);

			process.StandardInput.Write(Nonce);
			process.StandardInput.Close();

			string output = process.StandardOutput.ReadToEnd();

			process.WaitForExit();

			return output;
		}
	}
}

It has minimal dependencies and it should work on all platforms where .Net Core is supported. Here's example request:

curl -X POST http://localhost:5000/ -H "Content-Type: application/json" -d "{\"key_id\":\"A816B853B0C2A43A\",\"nonce\":\"CorrectHorseBatteryStaple\"}"

And a response:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA384

CorrectHorseBatteryStaple
-----BEGIN PGP SIGNATURE-----

iJUEARMJAB0WIQRyc5PcuFvhvxaRXKyoFrhTsMKkOgUCaHohZAAKCRCoFrhTsMKk
Ojl2AXwMpk9/u3O+f6D5KVBL+Yv/p3w15fXsYfGjQQbJit9Lb8wNHRs/jYiUB+y2
yujJbEsBfj3ijwAqFq4ZGIMRfQtf36z17StxUKk9MIkLLy66UPuanLIRCeS+wkAs
6DJP/F90UQ==
=hjNV
-----END PGP SIGNATURE-----

Gitea can directly issue challenge to it on http://localhost:5000 and the user will get prompted to enter password for their key_id by gpg-agent. Hope this helps.

@levicki commented on GitHub (Jul 18, 2025): Another option would be a signing helper console app, here's a minimal working code example in .Net 8.0 (note that not all possible error conditions are handled!): ``` namespace GiteaGPGSigner { using System.Diagnostics; using System.Net; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; internal class SignRequest { [JsonPropertyName("key_id")] public string KeyID { get; set; } [JsonPropertyName("nonce")] public string Nonce { get; set; } } internal class Program { static HttpListener m_Listener; static async Task Main() { m_Listener = new HttpListener(); m_Listener.Prefixes.Add("http://localhost:5000/"); m_Listener.Start(); Console.WriteLine("Gitea GPG signing server running on http://localhost:5000/"); while (true) { var ctx = await m_Listener.GetContextAsync(); _ = Task.Run(() => HandleRequest(ctx)); } } static void HandleRequest(HttpListenerContext ctx) { if (ctx.Request.HttpMethod != "POST") { ctx.Response.StatusCode = 405; ctx.Response.Close(); return; } try { using var reader = new System.IO.StreamReader(ctx.Request.InputStream, ctx.Request.ContentEncoding); var json = reader.ReadToEnd(); var req = JsonSerializer.Deserialize<SignRequest>(json); if (req == null || string.IsNullOrWhiteSpace(req.KeyID) || string.IsNullOrWhiteSpace(req.Nonce)) { ctx.Response.StatusCode = 400; return; } string signature = SignChallenge(req.KeyID, req.Nonce); byte[] buffer = Encoding.UTF8.GetBytes(signature); ctx.Response.ContentType = "text/plain"; ctx.Response.ContentLength64 = buffer.Length; ctx.Response.OutputStream.Write(buffer, 0, buffer.Length); } catch (Exception ex) { ctx.Response.StatusCode = 500; } finally { ctx.Response.Close(); } } static string SignChallenge(string KeyID, string Nonce) { var psi = new ProcessStartInfo { FileName = "gpg", Arguments = $"--clearsign --local-user {KeyID}", RedirectStandardInput = true, RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = false }; using var process = Process.Start(psi); process.StandardInput.Write(Nonce); process.StandardInput.Close(); string output = process.StandardOutput.ReadToEnd(); process.WaitForExit(); return output; } } } ``` It has minimal dependencies and it should work on all platforms where .Net Core is supported. Here's example request: ``` curl -X POST http://localhost:5000/ -H "Content-Type: application/json" -d "{\"key_id\":\"A816B853B0C2A43A\",\"nonce\":\"CorrectHorseBatteryStaple\"}" ``` And a response: ``` -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA384 CorrectHorseBatteryStaple -----BEGIN PGP SIGNATURE----- iJUEARMJAB0WIQRyc5PcuFvhvxaRXKyoFrhTsMKkOgUCaHohZAAKCRCoFrhTsMKk Ojl2AXwMpk9/u3O+f6D5KVBL+Yv/p3w15fXsYfGjQQbJit9Lb8wNHRs/jYiUB+y2 yujJbEsBfj3ijwAqFq4ZGIMRfQtf36z17StxUKk9MIkLLy66UPuanLIRCeS+wkAs 6DJP/F90UQ== =hjNV -----END PGP SIGNATURE----- ``` Gitea can directly issue challenge to it on `http://localhost:5000` and the user will get prompted to enter password for their `key_id` by `gpg-agent`. Hope this helps.
Author
Owner

@ieris19 commented on GitHub (Jul 18, 2025):

Potentially, it could be as simple as providing a small tabulated example (Unix-like/Windows) with an OS appropriate command in each. Then on the server, have Gitea verify against <token>\n or <token>\r\n based on the tab selected?

I think this one adds less complexity over requiring the user to download any sort of helper (whether that is a small server, an extension or anything else for that matter).

Gitea could potentially also just check against <token>\n and if failed, check against <token>\r\n, it wouldn't be that costly.

Gitea could also just choose which one to do first based on the User Agent, just like it could select the tab automatically opened based on it (user would always be free to switch tabs if the user agent is wrong)

@ieris19 commented on GitHub (Jul 18, 2025): Potentially, it could be as simple as providing a small tabulated example (Unix-like/Windows) with an OS appropriate command in each. Then on the server, have Gitea verify against `<token>\n` or `<token>\r\n` based on the tab selected? I think this one adds less complexity over requiring the user to download any sort of helper (whether that is a small server, an extension or anything else for that matter). Gitea could potentially also just check against `<token>\n` and if failed, check against `<token>\r\n`, it wouldn't be that costly. Gitea could also just choose which one to do first based on the User Agent, just like it could select the tab automatically opened based on it (user would always be free to switch tabs if the user agent is wrong)
Author
Owner

@levicki commented on GitHub (Jul 18, 2025):

As I said, Windows to my knowledge can't output with \n, only with \r\n and even things that can (like PowerShell commands) outputs UCS-2 (16-bit Unicode).

Silently including whitespace in a nonce and expecting user to handle that is bad design in my book.

Gitea could potentially also just check against <token>\n and if failed, check against <token>\r\n, it wouldn't be that costly.

And where does that kind of edge-casing stop? If user pastes Unicode do they also check if every other byte is \0 and silently convert Unicode to ANSI in that case? And what if it's Big Endian? Do they also check for that? And what if that Unicode string has invalid code points which convert to ?? Should they strip those out?

I am not saying they couldn't do that, but as a principal software engineer myself I think they shouldn't.

I also don't see a point of validating the gpg key in this way — if you input invalid gpg key, then your commits won't validate and show as properly signed. Not even GitHub is bothering with such checks because there's nothing you can gain by entering the wrong public gpg key into your own account.

@levicki commented on GitHub (Jul 18, 2025): As I said, Windows to my knowledge can't output with `\n`, only with `\r\n` and even things that can (like PowerShell commands) outputs UCS-2 (16-bit Unicode). Silently including whitespace in a nonce and expecting user to handle that is bad design in my book. > Gitea could potentially also just check against `<token>\n` and if failed, check against `<token>\r\n`, it wouldn't be that costly. And where does that kind of edge-casing stop? If user pastes Unicode do they also check if every other byte is `\0` and silently convert Unicode to ANSI in that case? And what if it's Big Endian? Do they also check for that? And what if that Unicode string has invalid code points which convert to `?`? Should they strip those out? I am not saying they couldn't do that, but as a principal software engineer myself I think they shouldn't. I also don't see a point of validating the gpg key in this way &mdash; if you input invalid gpg key, then your commits won't validate and show as properly signed. Not even GitHub is bothering with such checks because there's nothing you can gain by entering the wrong public gpg key into your own account.
Author
Owner

@ieris19 commented on GitHub (Jul 21, 2025):

I also don't see a point of validating the gpg key in this way

In my personal experience, this is very useful, it makes it so that I can genuinely test my GPG key without having to go make a commit and sign it somewhere. I think it's valuable, and regressing such a feature is probably pointless.

Unicode, Big Endian, and other edge cases should also probably be covered, but I understand that means software complexity and development time and that might not be desirable. But supporting the OS with the biggest market share is the bare minimum in my opinion. I run Linux on my main computer, and I appreciate open source as is, but I need Windows for my school work as well as work.

I think this should either be up to the user to handle or just silently checked against the two major line endings that are used by every operating system I know of. Like I said, a first assumption can be made based on UA and if that check fails, an alternative check can be performed against the other line ending. That and removing the quotes from the example should make this pretty much universal.

@ieris19 commented on GitHub (Jul 21, 2025): > I also don't see a point of validating the gpg key in this way In my personal experience, this is very useful, it makes it so that I can genuinely test my GPG key without having to go make a commit and sign it somewhere. I think it's valuable, and regressing such a feature is probably pointless. Unicode, Big Endian, and other edge cases should also probably be covered, but I understand that means software complexity and development time and that might not be desirable. But supporting the OS with the biggest market share is the bare minimum in my opinion. I run Linux on my main computer, and I appreciate open source as is, but I need Windows for my school work as well as work. I think this should either be up to the user to handle or just silently checked against the two major line endings that are used by every operating system I know of. Like I said, a first assumption can be made based on UA and if that check fails, an alternative check can be performed against the other line ending. That and removing the quotes from the example should make this pretty much universal.
Author
Owner

@levicki commented on GitHub (Jul 21, 2025):

In my personal experience, this is very useful, it makes it so that I can genuinely test my GPG key without having to go make a commit and sign it somewhere. I think it's valuable, and regressing such a feature is probably pointless.

Sorry, but the bolded part makes no sense. You seem to misunderstand the purpose of that check.

Commits are signed locally when you run git commit. You can verify with git log -1 --show-signature — no push needed.

Unless you paste the wrong GPG key into Gitea, your commit will verify fine after push.

If you want to test your GPG key, sign any file with gpg --sign and verify it — no commit required.

Gitea’s check only proves you own the matching private key. Other systems (GitHub, Azure) don’t bother, because it’s pointless — the worst that happens is your commit shows unsigned, and you fix it by pasting the correct public key and by running git commit --amend and git push --force.

TL;DR — IMO, the only check Gitea should perform when managing GPG, SSH keys, or other sensitive security settings is re-prompting your password. Allowing adding emails, setting them as primary without confirmation, and adding SSH and/or GPG keys all without password prompts opens doors for misuse if someone gains access to your logged-in session.

@levicki commented on GitHub (Jul 21, 2025): > In my personal experience, this is very useful, **it makes it so that I can genuinely test my GPG key without having to go make a commit and sign it somewhere**. I think it's valuable, and regressing such a feature is probably pointless. Sorry, but the bolded part makes no sense. You seem to misunderstand the purpose of that check. Commits are signed locally when you run `git commit`. You can verify with `git log -1 --show-signature` — no push needed. Unless you paste the wrong GPG key into Gitea, your commit will verify fine after push. If you want to test your GPG key, sign any file with `gpg --sign` and verify it — no commit required. Gitea’s check only proves you own the matching private key. Other systems (GitHub, Azure) don’t bother, because it’s pointless — the worst that happens is your commit shows unsigned, and you fix it by pasting the correct public key and by running `git commit --amend` and `git push --force`. TL;DR — IMO, the only check Gitea should perform when managing GPG, SSH keys, or other sensitive security settings is re-prompting your password. Allowing adding emails, setting them as primary without confirmation, and adding SSH and/or GPG keys all without password prompts opens doors for misuse if someone gains access to your logged-in session.
Author
Owner

@TechnickPoogi commented on GitHub (Jul 31, 2025):

Описание решения:
Шаги для решения проблемы:

  1. Откройте Git Bash

  2. Выполните команду:

    export PATH="/c/Program Files (x86)/GnuPG/bin:$PATH"  
    
  3. Модифицируйте команду подписи, добавив -n после echo, чтобы получилось:

    echo -n "[token]" | gpg -a --default-key [REDACTED] --detach-sig  
    
  4. Аккуратно скопируйте вывод (без переносов строк, без \r\n, должен остаться только \n после echo) и вставьте его в Gitea.
    Подпись будет успешно подтверждена.


Solution steps:

Steps to resolve the issue:

  1. Open Git Bash

  2. Run the following command:

    export PATH="/c/Program Files (x86)/GnuPG/bin:$PATH"  
    
  3. Modify the signing command by adding -n after echo, so it becomes:

    echo -n "[token]" | gpg -a --default-key [REDACTED] --detach-sig  
    
  4. Carefully copy the output (ensure no line breaks, only \n after echo, not \r\n) and paste it into Gitea.
    The signature should now verify successfully.

Also, in SSH key verify, developers used option "-n" in echo and even provided commands for cmd and powershell. If I have time, I will try to issue a PR for similar functionality for GPG

@TechnickPoogi commented on GitHub (Jul 31, 2025): **Описание решения:** Шаги для решения проблемы: 1. Откройте **Git Bash** 2. Выполните команду: ```bash export PATH="/c/Program Files (x86)/GnuPG/bin:$PATH" ``` 3. Модифицируйте команду подписи, добавив `-n` после `echo`, чтобы получилось: ```bash echo -n "[token]" | gpg -a --default-key [REDACTED] --detach-sig ``` 4. Аккуратно скопируйте вывод (без переносов строк, без \r\n, должен остаться только \n после echo) и вставьте его в Gitea. Подпись будет успешно подтверждена. --- **Solution steps:** Steps to resolve the issue: 1. Open **Git Bash** 2. Run the following command: ```bash export PATH="/c/Program Files (x86)/GnuPG/bin:$PATH" ``` 3. Modify the signing command by adding `-n` after `echo`, so it becomes: ```bash echo -n "[token]" | gpg -a --default-key [REDACTED] --detach-sig ``` 4. Carefully copy the output (ensure **no line breaks**, only \n after echo, not \r\n) and paste it into Gitea. The signature should now verify successfully. Also, in SSH key verify, developers used option "-n" in echo and even provided commands for cmd and powershell. If I have time, I will try to issue a PR for similar functionality for GPG
Author
Owner

@levicki commented on GitHub (Jul 31, 2025):

@TechnickPoogi You misunderstood the problem — problem is that Gitea expects \n to be in the token.

@levicki commented on GitHub (Jul 31, 2025): @TechnickPoogi You misunderstood the problem &mdash; problem is that Gitea expects `\n` to be in the token.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea#14542