Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Dec 12, 2022. It is now read-only.

[DEPRECATED] Windows helpers for GnuPG tools suite

License

NotificationsYou must be signed in to change notification settings

rupor-github/win-gpg-agent

Repository files navigation

  win-gpg-agent

DEPRECATION NOTE - September 2022

I amstopping development of this project as it is inherently unsecure and very difficult to properly support. Both because it is relying on GnuPG set of tools (you could find links to critique below if interested) and because the project itself in order to provide interoperability across different Windows sub-platforms implements unsafe solutions. Nobody should be forced to deal with such a complexity in everyday work. It became obvious to me that common practices recommend somewhat simpler solutions based on OpenSSH and its extensions and since GitHub now allows code signing using OpenSSH certificates - the whole reason for this monstrosity to exists is no more. In addition, there are a number of new open source products like age and minisign which are much simpler, could be argued about and have secure defaults. And since I am no longer using gpg-agent in my day to day - I am not planning for this project to follow further GnuPG development.

Simple set of tools to make working with GPG and SSH keys easier on Windows 10/11.

GitHub Release

Recent Windows hasssh-agent service (with support for persistence and Windows security) and I have been using itsuccessfully for a while. However there is another set of tools entirely -GnuPG. It implementsssh-agent functionality (with somewhat more flexibility than original), supports smart cards, attempts to handle identity aspects of security and sometimesmust be used (for example to sign git commits on some projects -this is an excellent explanation of code integrity aspect). All of that worksreasonably well on Linux practically out of the box.

Windows usage is a bit more problematic as we have to deal with various non-cooperating pieces: GnuPG win32 binaries are somewhat deficient, OpenSSH port integrated into Windows (console, terminal and all), Cygwin/MSYS2 ssh tools and WSL1 and WSL2 add challenges with specific binaries and different lifetime management requirements. Ideally we need to have Windows host to handle single set of secured keys (SSH and GPG) while transparently providing necessary interfaces to all other environments. This project aims to create simple set of tools to be combined with GnuPG binaries for Windows to do exactly that.

DISCLAIMER When using termGnuPG I amnot referring toGPG4Win, but rather to basic GnuPG tools built from code base common for all platforms. GPG4Win includes this set (which could be extracted), but normally it is available from GnuPG ftp siteftp.gnupg.org. It could be easily installed by usingscoop commandscoop install gnupg,chocolatey commandchoco install gnupg orwinget commandwinget install GnuPG. So no wonderful KDE GUIs ported to Windows.

I am still learning the full scope of damage one could cause by using GnuPG tools and I am certainly no expert here.

If you are interested in basic guides on how to handle keys using GnuPG tools - web is full of them and this project has nothing to do with it.This one is very good (albeit somewhat outdated). You could (and probably should) read set of excellent posts by Simon Josefsson:blog_1blog_2blog_3. To put things in perspective and select more practical place for PGP tools overall I strongly suggest studyingthis critique. It resonates a lot, especially after spending some time reading GnuPG code.

NOTE Eventually many pieces of functionality from this project will become obsolete. I am sure thatgpg-agent on Windows will directly support Windows OpenSSH server -T3883. Microsoft developers will finally decide how they want to handle security on Unix domain sockets and will changeOpenSSH port and many other wonderful things will happen. Until then we need to create specific translation layers to compensate for deficiencies. AssuanS.gpg-agent.ssh support in GnuPG code is presently broken under Windows (at least in GnuPG 2.2.25), so we have to resort to putty/pageant method instead (which today does not work in 64 bits GnuPG builds). And WSL2 requires additional layer of translation (withsocat on Linux side and either HYPER-V integration service or helper on Windows end) since AF_UNIX interop is not (yet? ever?) implemented for WSL2.

SECURITY NOTICE: All the usual security caveats applicable to WSL, SSH and GPG apply here. For example all interaction with the Win32 world happen with the credentials of the user who started the WSL environment. In practice,if you allow someone else to log in to your WSL environment remotely, they may be able to access the SSH keys stored inyour gpg-agent. This is a fundamental feature of WSL; if you are not sure of what you're doing, do not allow remote access to your WSL environment (i.e. by starting an SSH server).

COMPATIBILITY NOTICE: tools from this project were tested on Windows 10 and Windows 11 with multiple distributions and should work on anything starting with build 1809 - beginning with insider build 17063 and would not work on older versions of Windows 10, because it requiresAF_UNIX socket support feature. I started testing everything with "official" GnuPG LTS Windows build 2.2.27.

BREAKING CHANGES:

  • v1.4.0 changes default configuration values to support installation of 2.3+ GnuPG in non-portable mode. This required changing defaultgui.homedir and introducinggpg.socketdir to avoidgpg-agent sockets being overwritten byagent-gui due to name conflict. This change may require adjusting your configuration and usage scripts.

Installation

Installing using Scoop

    scoop bucket add extras    scoop install win-gpg-agent

Updating

    scoop update win-gpg-agent

Installing manually

Download archive from thereleases page and unpack it in a convenient location. For example:

using PowerShell

Push-Location-Path$env:USERPROFILE# Or, wherever you want the win-gpg-agent directory located$uriLatestWinGpgAgentZip=Invoke-RestMethod-Uri"https://api.github.com/repos/rupor-github/win-gpg-agent/releases/latest"|Select-Object-Property assets-ExpandProperty assets|Where-Object-FilterScript {$_.name-eq"win-gpg-agent.zip" }|Select-Object-Property browser_download_url-ExpandProperty browser_download_urlInvoke-WebRequest-OutFile"win-gpg-agent.zip"-Uri$uriLatestWinGpgAgentZipExpand-Archive .\win-gpg-agent.zipRemove-Item .\win-gpg-agent.zipPop-Location

NOTE Starting with v1.2.2 releases are packed with zip and signed withminisign. Here is public key for verification:

  RWTNh1aN8DrXq26YRmWO3bPBx4m8jBATGXt4Z96DF4OVSzdCBmoAU+Vq

Usage

  1. Make sure GnuPG works. Create/import keys, setup smart cards, etc.NOTE that WSL1/WSL2 distribution use case (while seems local and Windows native) does not mean that you should directly share gpg databases from Windows end even if you technically could. For all means and purposes those are "remote" cases - the only difference I could think of is usage ofS.gpg-agent socket rather than more restrictedS.gpg-agent.extra socket. Multiple WSL1 instances could probably share database and multiple WSL2 instances could probably share databases, but in general each distro should have its own. If you need more details - read gpg man pages. To put it simply: you still need to exportpublic keys on Windows end and import them on remote end, even if this means simply using
    gpg --export --armor user@example.org ...    gpg --import ...
  1. If you are using Windows native ssh-agent - stop it. You may want to delete all keys from its vault - you will need those keys in gpg vault instead.
Stop-Service ssh-agentSet-Service-StartupType Disabled ssh-agent
  1. If you would like to use Cygwin/MSYS2 ssh tools (as is the case by default withGit4Windows) you may want to consider placinggui.openssh: cygwin in agent-gui config file. Or you may add following line to your home directory .bashrc:
export SSH_AUTH_SOCK=$(cygpath${WSL_AGENT_HOME})/S.gpg-agent.ssh.cyg

Or you may consider switching it towin32-openssh (installed as a Windows feature or more recent version via scoop) by setting GIT_SSH environment variable on Windows side:

$Env:GIT_SSH="$(scoop prefix win32-openssh)/ssh.exe"

NOTE that in any case you need to manageSSH_AUTH_SOCK environment variable value on on either side per environment. It has to point to named pipe for Windows OpenSSH to work and to Cygwin socket file for Cygwin/MSYS2 tools andboth sets are using the same variable name.

  1. Runagent-gui.exe

Here is a diagram to show simplified relationship between parts:parts

Unfortunately due to environment complexity it is difficult to provide simple step-by-step guide. I will try to explain what each piece does (as they could be used separately from each other) and then provide an example setup.

There are presently 3 executables included in the set:agent-gui.exe,pinentry.exe andsorelay.exe

agent-gui.exe

GUI wrapper for gpg-agentVersion:1.0.0 (go1.15.6)Usage: agent-gui.exe [-dh] [-c path] -c, --config=path  Configuration file [agent-gui.conf] -d, --debug        Turn on debugging -h, --help         Show help

Is is a simple "notification tray" applet which doesgpg-agent.exe lifetime management. When started it will

  • attempt to locate GnuPG installation and start gpg-agent with "proper" command line parameters.
  • make sure that gpg-agent will usepinentry.exe from the same directory where agent-gui.exe is.
  • make sure that it functions by communicating with it.
  • create AF_UNIX socket counterparts for Assuan sockets from gpg-agent (except "browser" and "ssh" ones) and handle translation. I have no use for "browser" and S.gpg-agent.ssh presently does not work on Windows.
  • create and service named pipe for Windows native OpenSSH.NOTE OpenSSH (native and Cygwin) and AF_UNIX socket and named pipe are using pageant protocol to talk to gpg-agent.
  • create and service Cygwin socket for Cygwin/MSYS2 build of OpenSSH.NOTE OpenSSH (native and Cygwin) and AF_UNIX socket and named pipe are using pageant protocol to talk to gpg-agent.
  • Prepare TCP socket to service XAgent protocol and make it properly discoverable by XShell (create necessary windows etc).NOTE Socket will be using pageant protocol to talk to gpg-agent.
  • create and service tcp socket on "localhost:extra_port" for Win32-OpenSSH redirection (it does not presently supports unix socket redirection). This requres configuration and is disabled out of the box.
  • set environment variableSSH_AUTH_SOCK on Windows side to point either to pipe name so native OpenSSH tools know where to go or to Cygwin socket file to be used with Cygwin/MSYS2 ssh binaries.
  • createWIN_GNUPG_HOME,WSL_GNUPG_HOME,WIN_GNUPG_SOCKETS,WSL_GNUPG_SOCKETS,WIN_AGENT_HOME,WSL_AGENT_HOME environment variables, setting them to point to directories with Assuan sockets and AF_UNIX sockets and register those environment variables with WSLENV for path translation. Basically WSL_* would be paths on the Linux side and WIN_* are Windows ones. This way every WSL environment started after will have proper "unix" and "windows" paths available for easy scripting.
  • serve as a backend forgclpr remote clipboard tool.NOTE Starting with v1.1.0 gclpr server backend enforces protocol versioning and may require upgrade of gclpr.

You could always see what is going on by clicking "Status" on applet's menu:

status

Reasonable defaults are provided (but could be changed by using configuration file). Full path to configuration file could be provided on command line. If not program will look foragent-gui.conf in the same directory where executable is. It is YAML file with following defaults:

gpg:install_path:"${ProgramFiles(x86)}\\gnupg"homedir:"${APPDATA}\\gnupg"socketdir:"${LOCALAPPDATA}\\gnupg"gui:debug:falsesetenv:trueopenssh:nativeignore_session_lock:falsedeadline:1mxagent_cookie_size:16pipe_name:"\\\\.\\pipe\\openssh-ssh-agent"homedir:"${LOCALAPPDATA}\\gnupg\\agent-gui"gclpr:port:2850

Full list of configuration keys:

  • gpg.install_path - installation directory of GnuPG suite
  • gpg.homedir - will be supplied to gpg-agent on start as --homedir
  • gpg.socketdir - gnupg 2.3+(T5537) being installed in non-portable mode creates sockets in directory, different from homedir. To be exact default home directory continues to be${APPDATA}\gnupg, but sockets are now created in${LOCALAPPDATA}\gnupg. Changinggpg.homedir to${LOCALAPPDATA}\gnupg does not help - gnupg will use subdirectory of${LOCALAPPDATA}\gnupg deriving name of sha1 hash with "d." prepended to it. This configuration allows to compensate this - if set it will be used by win-gpg-agent to locate sockets created by gpg-agent proper while keeping home directory unchanged. Make sure thatgpg.socketdir andgui.homedir are not pointing to the same location or socket names for gpg-agent and agent-gui will overlap causing havoc. If explicitly set to empty stringgpg.homedir value will be used instead
  • gpg.use_standard_pinentry - if absent or set tofalse (default) pinentry supplied with win-gpg-agent will be used no matter what is specified in gnupg gpg-agent configuration. If set totrue win-gpg-agent would not force command line overwrite allowing you to use gpg-agent.conf instead.
  • gpg.gpg_agent_conf - if defined will be supplied to gpg-agent on start
  • gpg.gpg_agent_args - array of additional arguments to be passed to gpg-agent on start. No checking is performed
  • gui.debug - turn on debug logging. UsesOutputDebugStringW - use Sysinternalsdebugview to see
  • gui.setenv - automatically prepare environment variables
  • gui.openssh - when value iscygwin set environmentSSH_AUTH_SOCK on Windows side to point to Cygwin socket file rather then named pipe, so Cygwin and MSYS2 ssh build could be used by default instead of what comes with Windows.
  • gui.extra_port - Win32-OpenSSH does not know how to redirect unix sockets yet, so if you want to use windows native ssh to remote "S.gpg-agent.extra" specify some non-zero port here. Program will open this port on localhost and you can use socat on the other side to recreate domain socket. By default it is disabled
  • gui.xagent_cookie_size - Size of the cookie used to perform XAgent protocol handshake. If set to 0 XAgent server would not be started at all. SeeXShell for details.
  • gui.ignore_session_lock - continue to serve requests even if user session is locked
  • gui.pipe_name - full name of pipe for Windows OpenSSH
  • gui.homedir - directory to be used by agent-gui to create sockets in
  • gui.deadline - since code which does translation from Assuan socket to AF_UNIX socket has no understanding of underlying protocol it could leave servicing go-routine handing forever (ex: client process died). This value specifies inactivity deadline after which connection will be collected
  • gui.gclpr.port - server port forgclpr backend
  • gui.gclpr.line_endings - line ending translation forgclpr backend
  • gui.gclpr.public_keys - array of known public keys forgclpr backend

pinentry.exe

Pinentry program for GnuPG        1.0.0 (go1.15.6)Usage: pinentry.exe [-dh] [-c path] [--version] -c, --config=path  Configuration file [C:\Users\mike0\.wsl\pinentry.conf] -d, --debug        Turn on debugging -h, --help         Show help     --version      Show version information

It is pretty mundane pinentry implementation, I tried to follow everything I could find from GnuPG documentation and pinentry code. Since it is using WIndows Credentials API to show GETPIN dialogs a lot of "visuals" from pinentry protocol are either useless or cannot be easily implemented (timeouts, display settings etc).

I think it could be used as pinentry replacement on Windows even without agent-gui (for example to be called from WSL gpg if you decide to keep your vault there and ignore WIndows GnuPG completely) to show proper GUI dialogs:

onetwo

If you let it - it will save passwords in Windows Credential Manager as "Generic Credentials" providing decent level of convenience and integration:

three

NOTE Starting with 1.6.0 "Remember me" check box will initially be unchecked (previously it was always checked) and pinentry will use its last used state next time.

Configuration file is almost never needed, but just in case full path to configuration file could be provided on command line. If not program will look forpinentry.conf in the same directory where executable is. It is YAML file with following defaults:

gui:debug:falsepin_dialog:delay:300msname:Windows Securityclass:Credential Dialog Xaml Host
  • gui.debug - turn on debug logging. UsesOutputDebugStringW - use Sysinternalsdebugview to see
  • gui.pindialog.* - since gpg-agent starts pinentry which in turn calls Windows APIs to show various dialogs often due to the timing resulting dialog could be left in the background. Those parameters specify artificial delay and name/class for window to be attempted to be brought into foreground forcefully.

sorelay.exe

Socket relay program for WSL        1.0.0 (go1.15.6)Usage: sorelay.exe [-adh] [-c path] [--version] path-to-socket -a, --assuan       Open Assuan socket instead of Unix one -c, --config=path  Configuration file [C:\Users\mike0\.wsl\sorelay.conf] -d, --debug        Turn on debugging -h, --help         Show help     --version      Show version information

This is helper program along the lines of John Starks'npiperelay.exe. Put it somewhere on devfs for interop to work its magic and combine with socat on WSL2 side and you could easily convert both Windows Assuan and Windows AF_UNIX sockets into sockets on WSL2 Linux end.

As an example (use your path and proper escaping) following will translate Windows side Assuan socket:

( setsid socat UNIX-LISTEN:/home/rupor/.gnupg/S.gpg-agent,fork EXEC:"${HOME}/winhome/.wsl/sorelay.exe -a c\:/Users/mike0/AppData/Local/gnupg/S.gpg-agent",nofork& )>/dev/null2>&1

And this (use your path and proper escaping) will translate Windows side AF_UNIX socket:

( setsid socat UNIX-LISTEN:/home/rupor/.gnupg/S.gpg-agent,fork EXEC:"${HOME}/winhome/.wsl/sorelay.exe c\:/Users/mike0/AppData/Local/gnupg/S.gpg-agent",nofork& )>/dev/null2>&1

Youreally have to be on WSL2 in order for this to work - if you see errors likeCannot open netlink socket: Protocol not supported - you probably are under WSL1 and should just use AF_UNIX sockets directly. Runwsl.exe -l --all -v to check what is going on. When on WSL2 make sure that socat is installed and sorelay.exe is on windows partition and path is right.

Configuration file is never needed, but just in case full path to configuration file could be provided on command line. If not program will look forsorelay.conf in the same directory where executable is. It is YAML file with following defaults:

gui:debug:false

Troubleshooting

In most cases all what's required is a simpleagent-gui.conf adgustment, however sometimes with non typical installations you may need to dig diper and try to understand what is going on both in agent-gui and in underlying gpg-agent. Here are couple of pointers:

  • In many cases to see what is going on you just have to look at ssh debug trace, something likessh -vvv host.
  • All agent-gui components have debug switch to activate additional logging. Internally logging is usingWin32 OutputDebugString API call - so you would need to use debugger or tool likeSysinternals DebugView to see and capture it.
  • When this is not enough you may want to turn on debug logging in GnuPG tools, it is pretty well documented but just in case: I have scoop basedportable GmuPG installation (gpgconf.ctl is present in bin subdirectory of installation). In order to see full trace of gpg-agent I create${APPDATA}\gnupg\gpg-agent.conf (exact location depends on your installation) with following content:
debug-alldebug-level gurulog-file "local/path/to/the/log/file"verboseverboseverbose

Before creating issues and asking for help, please, see if you could diagnose what is going on - you'd need to do this anyways and this will save everybody a lot of time. Remember -win-gpg-agent tools are making GnuPG integration with various variants of WIndows environments easier, but they would not provide any functionality GnuPG tools do not provide. So always make sure that what you want is actually supported by original GnuPG set.

Example

Putting it all together nicely -remote here refers to your wsl shell or some other box or virtual machine you couldssh to. Goal here is to have a setup which could be used the same way in different Linux instance with minimal changes and customization - be it native Linux install, something I ssh into or WSL distro running. We should be able to use a small set of safely stored private keys and be able to forward both gpg and ssh everywhere with minimal complexity (at least it should be manageable).

For my WSL installations I always create~/winhome and link it to my Windows home directory (where I have.wsl directory with various interoperability tools from Windows side). I am assuming thatgclpr is in your path onremote and you installed it's Windows counterpart somewhere indrvfs location (~/winhome/.wsl is a good place).

I auto-startagent-gui.exe on logon on my Windows box - no special customization is needed (except forgclpr public keys from various locations I would like to share my clipboard with)

I am using scoop forGnuPG andwin-gpg-agent installations which results inportable GnuPG mode. With gnupg 2.3.3 releasegpg.socketdir is not required and must be set to empty string in config file. With gnupg 2.3.4 configuration must be changed yet again. Look for up to date comments in scoop installation manifestwin-gpg-agent.json oragent-gui.conf after installation. In your scripts you may need to useWIN_GNUPG_HOME orWIN_GNUPG_SOCKETS environment variables to properly setup socket paths as they change from version to version. Please pay attention, code below is an example and may need modification.

In my .bashrc I detect what I have and where it runs using code like this:

# detect what we haveif uname -a| grep -q Microsoft;then# WSL 1 could use AF_UNIX sockets from Windows side directlyif ["${WSL_AGENT_HOME}" ];thenexport GNUPGHOME=${WSL_AGENT_HOME}export SSH_AUTH_SOCK=${WSL_AGENT_HOME}/S.gpg-agent.sshfielif uname -a| grep -q microsoft;then# WSL 2 needs help from socat/sorelay${HOME}/.local/bin/win-gpg-agent-relay startexport SSH_AUTH_SOCK=${HOME}/.gnupg/S.gpg-agent.sshelse# Do whatever -- this is real Linuxfi

Wherewin-gpg-agent-relay is heavily based on the work of othersNOTE It is for Debian based distros only!

My.ssh/config entries used tossh toremote have port forwarding enabled forgclpr:

RemoteForward 2850 127.0.0.1:2850

Onremote mytmux.conf includes following lines:

# --- clipboard -------------------------------------------------------------------set -g set-clipboard offif-shell'if [ -n ${WSL_DISTRO_NAME} ]; then true; else false; fi' \'bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "~/winhome/.wsl/gclpr.exe copy" ; bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "~/winhome/.wsl/gclpr.exe copy"' \'bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "gclpr copy" ; bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "gclpr copy"'

And myneovim configuration fileinit.vim onremote has following lines:

setclipboard+=unnamedplusifhas("unix")" ----- on UNIX ask lemonade to translate line-endingsifempty($WSL_DISTRO_NAME)ifexecutable('gclpr')letg:clipboard= {\'name':'gclpr',\'copy': {\'+':'gclpr copy',\'*':'gclpr copy',\   },\'paste': {\'+':'gclpr paste --line-ending lf',\'*':'gclpr paste --line-ending lf',\  },\'cache_enabled':0,\}endifelse" ---- we are inside WSL - reach out to the Windows sideifexecutable($HOME .'/winhome/.wsl/gclpr.exe')letg:clipboard= {\'name':'gclpr',\'copy': {\'+':$HOME .'/winhome/.wsl/gclpr.exe copy',\'*':$HOME .'/winhome/.wsl/gclpr.exe copy',\   },\'paste': {\'+':$HOME .'/winhome/.wsl/gclpr.exe paste --line-ending lf',\'*':$HOME .'/winhome/.wsl/gclpr.exe paste --line-ending lf',\  },\'cache_enabled':0,\}endifendifendif

Using SSH and Linux you could remote GnuPG extra socket as far as you want by adding something like this to you.ssh/config where you want it:

RemoteForward /home/rupor/.gnupg/S.gpg-agent /home/rupor/.gnupg/S.gpg-agent.extra

In case you prefer to use Win32-OpenSSH you will need to setgui.extra_port in configuration and RemoteForward it, using something like

socat UNIX-LISTEN:/run/user/1000/gnupg/S.gpg-agent,fork TCP4-CONNECT:127.0.0.1:$extra_port

on remote to recreate domain socket.

Just followthis guide - it will allow you to sign you git commits everywhere using single private key while keeping it in a single safe place (like smart card). You will still have to distribute and import public key in multiple places, which may be inconvenient but should be secure. You couldread a bit more on that.

Credits

Icons used are downloaded fromIcon Archive, they all allow non commercial free use and are copyrighted by authors.


[8]ページ先頭

©2009-2025 Movatter.jp