The OpenSSH port shipping with new versions of Windows uses Windows named pipes for interprocess communication. The enable-ssh-support option for gpg-agent should be extended on Windows to support named pipes in addition to Cygwin/MSYS emulation of Unix sockets, or a new option should be added to Windows for this, so that "native" ssh client can be used instead of requiring Cygwin ssh client or PuTTY.
Thanks for the pointer. But as long as the Windows ssh server is that instable I see no urgent need to add this to GnuPG.
BTW, can you confirm that gpg-agent works with the Cygwin SSH? IIRC, I once added a hack to allow for this but never thoroughly tested it.
I would argue that the Windows port of OpenSSH is not unstable at this point, especially given that Microsoft is even providing it as an installable feature in the next regular Windows 10 release. The fact that the port is now using actual OpenSSH version numbers instead of their own 0.x versions lends credence to this as well.
As for Cygwin, it's been so long since I needed to use the Cygwin or MSYS builds of the OpenSSH client that I didn't even realize I still had it installed. However, after checking with both latest version of Cygwin and latest 64-bit MSYS2, gpg-agent doesn't work with their ssh client packages. Trying to use the S.gpg-agent.ssh "socket" results in this error message when attempting to access the agent via ssh, ssh-add, etc.:
Error connecting to agent: Bad file descriptor
Rhat's for the client, right. I never used it. We used to run a Windows 8 instance in a VM to run tests via ssh on it. That worked most not really stable. For obvious reasons I am more interested in the server part ;-)
The Cygwin thing was a quick and untested hack. I don't think it makes much sense to follow up on this. Better to support the native ssh thing.
I've been working with one of Microsoft's developers on a temporary tool that should bridge the connection between named pipes and the Unix sockets emulation used by gpg-agent but things appear to trip up with sending the nonce. From the position of the tool, the nonce value is successfully sent (send returns 16), but never seems to be picked up by gpg-agent. Instead both gpg-agent and the bridge sit there until whatever tool is using them (I test using ssh-add -l) is terminated, at which point gpg-agent immediately spits up the message
gpg-agent: error reading nonce on fd 660: Input/output error
(PID and FD variable, of course.)
I just took a look through assuan-socket.c and it appears that we just need to send the nonce and don't need to read anything back. We also found a bug on our side that was preventing the nonce from being sent, which has been fixed. The error message logged above no longer happens.
Now however, as soon as the nonce is sent across, we get log messages like
gpg-agent: ssh handler 0x3 for fd 844 started gpg-agent: ssh handler 0x3 for fd 844 terminated
It appears that the actual ssh-agent message coming across the bridge is never read or acted upon, but the socket connection isn't closed despite the log message stating that the handler is terminated.
@werner I was hoping to make a modified gpg-agent build that would let me walk through what's going on after the nonce is sent but it looks like the gpg4win process only takes in a package of pre-built gpg binaries which rules that out. As far as I can figure out, after the nonce is read and accepted, libassuan creates a stream object out of the socket and then finding nothing in the stream terminates the ssh handler. We send the actual client request immediately after the nonce but in a separate call to send() so I now wonder if by not having anything read in at the same time as the nonce gpg-agent or libassuan thinks that it's a 0-length stream.
Although I don't use the ssh client on Windows I had to integrate the Windows ssh server into our release process (GlobalSign sent us a Windows-only token, for the new cert and so we can't anymore use osslsigncode). The ssh server is really stable and so it makes a lot of sense to better integrate our ssh-agent into Windows.
I need to look into their named pipes IPC - I once ruled that out for Windows because it is not possible to limit connections to the local machine.
In the meantime you can use . I have tested with ssh key on yubikey and AuthenticationMethods publickey, win32-ssh (or ssh-portable, which is the new repository name) correctly works with gpg and pinentry is called. Despite it being called wsl, wsl environment is not required.
I'm actually trying to do the following:
I have 2 Windows PCs at home: Laptop and Desktop.
I'm using Windows' native OpenSSH client and server so I can connect to my desktop using my laptop.
I want to edit a file while on SSH that's placed on my desktop, and then run git commit so I can save my work.
The problem is my Git is configured to ask for a GPG key, that has a password. Since I'm over SSH, the GnuPG window asking for such password can't be rendered and my Desktop gets stuck at this step.
What I'm looking for is a way to forward this password prompt to my laptop, where I can then sign my commit through SSH.
Is such a thing possible? And does WSL SSH Pageant work for the process I mentioned?
P.S.: local commit signing (without SSH connections) is working on both machines, they both have the same GPG keys and config for Git and GnuPG.
P.S.²: I never used any graphical GPG client (Pageant, gpg4win, etc), I just use GPG to sign Git Commits through the CLI.
@bvieira You need to set pinentry-mode=loopback for gpg program used in git.
On unix systems GPG_TTY=$(tty) makes it work. But not sure on windows how this logic is handled.
So you might have to use git --config global gpg.Program and try passing pinentry-mode. Not sure if you can pass arguments to it directly, otherwise might have to create a wrapper batch file.
Unfortunately you can't pass extra arguments.
loopback mode won't help; it is simply that we don't support the integrated OpenSSH yet. The Putty support uses a different IPC mechanism than our inter-GnuPG-IPC which is again different from OpenSSH for Windows.
There is a user report that got things to work with https://github.com/rupor-github/win-gpg-agent
Though this took some time to find out for the user. So if this is not implemented soon, we should improve the documentation about works and what does not.
Lots of detailed documentation but frankly, after a brief read I have not yet figured out what it really does. We won't support Cygwin stuff - this is all obsolete and awe also removed starting gpg-agent as a service for good reasons. Instead of starting gpg-agent with lot of command line args it would be better to put this into a per user or system wide config file.
Since Windows user naively could expect multiple methods of accessing certificates from different programs (or sometimes from the same program but different supported environments, like Git4Win and git in WSL) to work together transparently, win-gpg-agent covers translation of one accidentally supported method (32 bit putty shared memory) to multiple unsupported ones (named pipe, cygwin, etc). It also takes care of managing gpg-agent.exe lifetime tying it to user login session for convenience. It uses command line parameters to only to overwrite staff critical to its functionality and does not prevent user from having configuration file(s). Optionally it provides pinentry which is integrated with Windows native Crypto Vault and UX rather than using wonderful QT or GTK. As specified in documentation when developers of gpg and WIndows will get their act together and figure out what they want and how they want it - most of functionality would not be needed. I would like to point out that simply claiming superiority and not supporting cygwin (Git4Win) or working Assuan ssh socket or putty shared memory in 64 bits Windows build does not help with user experience a single bit.
@rupor-github thanks for your explanations and the contribution to the GnuPG and crypto Free Software code base!
My experience with @werner is that there are usually good reason why he prefers one over the other thing. And sometimes things to not get work upon for a while, because resources are limited. Any questions or suggestions are always made under these preconditions of the current understanding. As most people in Free Software work as good as they can (and wth the resources they have available), I think suggesting to anybody to get their act together is not helpful. Also I saw nobody claiming superiority. Please ask or propose something more specific to improve understanding and the situation.
@bernhard thank you for explaining, did not mean to offend anybody. Before creating win-gpg-agent I tried to read as much as I could on a history and obviously had to study source a bit. Be it as it may - I decided to have separate wrapper, rather then contributing directly to gpg code base. There is noticable number of use cases on Windows which presently not addressed, some I believe are sitting it the queue already.
Fix non working assuan ssh socket?
Provide working 64 bit build including putty shared memory protocol?
Start communicating with other developers on clean future path (so cygwin solutions could be adjusted)?
Support windows named pipes so whatever comes with Windows works out of the box rather than explaining why name pipes are bad?
Not sure if that is helpful.
@rupor-github no problem! :)
As to your suggestions. The status of this issue, as far as I understood from reading it is:
Werner has accepted that using the native Windows ssh (an OpenSSH port) with the names pipes they use, is a valid and useful use-case. He now needs time to read up on the named pipes, their properties and come up with the code.
(If anybody else comes up with well documented code or links to very good technical documentation, it may help the process.)
This seems to be the focus of this issue. (And the remark made at laast by @werner seem to be part explanation of the history, stating his status that he could not yet fully read and understand the https://github.com/rupor-github/win-gpg-agent documentation and some minor suggestions/thoughs.)
As for the two remaining suggestions:
- working 64 bit build for putty shared memory protocol
- cygwin solutions improvement.
The next step forward for those would be to have separate new issues and get them to be understood well.
(Re 1 my understanding was that putty is working in principle, but I'm not sure about what it is about the 64 bit build.)
(Re 2: As for cygwin maybe an email to gnupg-devel or some cygwin mailinglist explaining the challenges can be helpful?)
@bernhard Sorry for the delayed answer, was on sabbatical.
There are 2 putty versions 32 bits and 64 bits, both are working. Now there is 32 bit version of GnuPG tools which successfully pretends to be putty (implements shared memory protocol). I could build 64 bits GnuPG without a problem, however it does a bad job pretending to Putty - when I try to access shared memory it does not work (crashes the other side).
Also last time I looked for whatever reasons Assuan S.gpg-agent.ssh support in GnuPG code was broken under Windows (there was a comment in the code on that)
I am not exactly sure how to improve cygwin solutions support and have no intention messing with egos on cygwin list. My understanding is that presently (WSL and everything) cygwin is not really needed. Unfortunately most widely used Git4Windows is built on cygwin platform so any "successful" and user friendly solution should consider this for time being...
@rupor-github no problem for the delay. Thanks for explaining!
Now I can see that there is at least the Putty 64bit support, which should be put in a new issue.
With Assuan S.gpg-agent.ssh support in GnuPG code was broken under Windows, this maybe part of this issue already or not, I technically do not know enough to guess about this. So it is probably good to wait until werner gets a go at this issue. (Which take a while.)
I think that the last argument of CreateNamedPipeA can limit the access to the named pipe.
The descriptor I use (in my patch) is:
I don't know this semantics well (I just copied from ssh-agent implementation of Win32-OpenSSH).
Here is the parser output:
$ python3 sd.py --type=pipe "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;0x12019b;;;AU)" D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;0x12019b;;;AU) Discretionary ACL: P(A;;GA;;;SY)(A;;GA;;;BA)(A;;0x12019b;;;AU) Flags: P: SE_DACL_PROTECTED (Blocks inheritance of parent's ACEs) ACE 1: A;;GA;;;SY Type: A (ACCESS_ALLOWED_ACE_TYPE) Access rights: GA (0x10000000) 0x10000000 GENERIC_ALL (Generic right mapped to every other existing right) Trustee: SY (S-1-5-18) (Local System) ACE 2: A;;GA;;;BA Type: A (ACCESS_ALLOWED_ACE_TYPE) Access rights: GA (0x10000000) 0x10000000 GENERIC_ALL (Generic right mapped to every other existing right) Trustee: BA (S-1-5-32-544) (Administrators) ACE 3: A;;0x12019b;;;AU Type: A (ACCESS_ALLOWED_ACE_TYPE) Access rights: 0x12019b 0x100000 SYNCHRONIZE (Wait for a change in the object, standard to all types) 0x20000 READ_CONTROL (Read the object's security descriptor except its SACL, standard to all types) 0x100 FILE_WRITE_ATTRIBUTES (Write the pipe's attributes) 0x80 FILE_READ_ATTRIBUTES (Read the pipe's attributes) 0x10 FILE_WRITE_EA (Write the pipe's extended attributes, if any) 0x8 FILE_READ_EA (Read the pipe's extended attributes, if any) 0x2 FILE_WRITE_DATA (Write contents into the pipe) 0x1 FILE_READ_DATA (Read contents from the pipe) Trustee: AU (S-1-5-11) (Authenticated Users)