WSL 调用 Kleopatra 实现 Yubikey 硬件GPG签名

背景

在 2022 年全球国际局势紧张,网络安全环境高度受威胁的环境下,声明自己的代码主权尤为重要 。 我们的身份可能会被伪造,进而发布投毒的代码,然后攻击波及到某个100k star的项目,还需要自己背锅。为了避免这种情况发生,更为了拥有一个炫酷的小标志,在WSL里调用yubikey签名迫在眉睫,间不容发!

image-20220902183550039

前置知识

要用硬件key跨VM签名,多少得了解GPG签名,yubikey是什么,以及如何在GitHub上使用yubikey。

那么这里是 简明 GPG 概念 – 知乎 (zhihu.com)

这里是 使用 Yubikey 存储 GPG Key 以及认证 SSH 登录 · Coda

这里是 在Github上使用GPG的全过程 – 知乎 (zhihu.com)

解决方案

WSL 1

先上结论,不要浪费时间:利用WSL 1NT Kernel with syscall trans,系统端口相通,直接翻译socket访问端口。

gpg --import $your_key

保存下面的代码为脚本,并加入.bashrc

#!/bin/bash

WinUserName="change here plz!"
rm $HOME/.gnupg/S.gpg-agent*
GPG_AGENT="/mnt/c/Users/"$WinUserName"/AppData/Local/gnupg/S.gpg-agent"
PREPEND_FILE="/tmp/gpg_agent_prepend"
WINDOWS_GPG_AGENT_PORT=$(head -n1 "$GPG_AGENT")
tail -n+2 "$GPG_AGENT" >"$PREPEND_FILE"
nohup socat "UNIX-LISTEN:$HOME/.gnupg/S.gpg-agent,fork" "SYSTEM:cat \"$PREPEND_FILE\" - <&3 | socat STDIO \"TCP\:127.0.0.1\:$WINDOWS_GPG_AGENT_PORT\" >&4,fdin=3,fdout=4" >/dev/null 2>&1 &

其逻辑是:

  1. 导入你的GPG公钥,需要pubring.kbxtrustdb.gpg中的公钥信息寻找密钥。
  2. 移除Linux自带的gpg-agent,因为VM内的Linux系统无法访问USB端口,所以需要劫持这里的socket,拦截GPG请求。
  3. 从windows下Kleopatra的agent提取端口(代表着监听端口)
  4. 从win的agent中提取二进制内容,并且写入$PREPEND_FILE 中,这个二进制内容代表什么我还没研究。
  5. 利用socat$HOME/.gnupg/S.gpg-agent (步骤2中移除的socket)监听请求。
    • UNIX-LISTEN:监听socket端口
    • SYSTEM:转发输入输出,对象为后续的命令。
    • cat $PREPEND_FILE - < &3|
      首先输出$PREPEND_FILE的内容,后续转发fd=3的输入到输出。
    • socat STDIO \"TCP\:127.0.0.1\:$WINDOWS_GPG_AGENT_PORT\" >&4
      监听标准输入输出stdin/stdout,将其转发到Kleopatra监听的TCP端口下。
      此时的STDIO作用域仅限于这句子命令,STDOUT被重定向到 fd=4
    • fdin=3,fdout=4,传给SYSTEMstdin输入重定向到fd=3,将fd=4的输出作为SYSTEM字段的STDOUT
    • 这么做的原因是避免在标准输入输出上产生大量信息,发生干扰。
  6. nohup ** >/dev/null 2>&1 &,后台执行,不输出日志和错误信息。如果你要调试,请删除这部分

然后,加入.bashrc,可以使用gpg --card-status快乐的查看结果辣。

image-20220902203631055

WSL 2

同理,先上结论。原理和WSL1类似,由于WSL2的网络特性,略有调整。

首先在Windows下开启WSL2的防火墙,允许访问主机端口(管理员权限,cmd/PS),只用执行一次

New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow

[不建议] 然后在每次开机之后,用管理员权限的终端,执行一个端口转发条例,其中需要自行找到 GPG_PORTWSL_ROUTER_IP

netsh.exe interface portproxy del v4tov4 listenport=$GPG_PORT listenaddress=$WSL_ROUTER_IP  connectport=$GPG_PORT connectaddress=127.0.0.1

当然,这样非常不优雅。所以个人强烈建议安装一个gsudo(可以通过scoop),可以在WSL2中自动执行该指令

之后步骤同WSL1导入gpg共钥,添加脚本。但是脚本略有调整。

#!/bin/bash

WinUserName="change here plz!"
HOST_IP=$(cat /etc/resolv.conf |grep "nameserver" |cut -f 2 -d " ") # JUST FOR WINDOWS
rm $HOME/.gnupg/S.gpg-agent*
GPG_AGENT="/mnt/c/Users/"$WinUserName"/AppData/Local/gnupg/S.gpg-agent"
PREPEND_FILE="/tmp/gpg_agent_prepend"
WINDOWS_GPG_AGENT_PORT=$(head -n1 "$GPG_AGENT")

WIN_FORWARD=$(netstat.exe -ano | grep "$HOST_IP:$WINDOWS_GPG_AGENT_PORT" | wc -l)
if [ $WIN_FORWARD -eq 0 ];then # PREVENT POP-UP WINDOW OF UAC EVERYTIME!
gsudo.exe netsh.exe interface portproxy add v4tov4 \
listenport=$WINDOWS_GPG_AGENT_PORT listenaddress=$HOST_IP \
connectport=$WINDOWS_GPG_AGENT_PORT connectaddress=127.0.0.1
fi
tail -n+2 "$GPG_AGENT" >"$PREPEND_FILE"
nohup socat "UNIX-LISTEN:$HOME/.gnupg/S.gpg-agent,fork" "SYSTEM:cat \"$PREPEND_FILE\" - <&3 | socat STDIO \"TCP\:$HOST_IP\:$WINDOWS_GPG_AGENT_PORT\" >&4,fdin=3,fdout=4" >/dev/null 2>&1 &

其中增加了如下几点:

  1. 使用resolv.conf 获取宿主机的IP,因为WSL2使用NAT的方式访问,所以需要访问网关。
  2. 使用gsudo临时获取管理员权限,netsh.exegpg-agent仅在127.0.0.1上的监听,转发给WSL2的网关地址,让WSL2可以直接访问。
  3. 使用netstat.exe检测netsh.exe的转发规则是否工作,避免每次都要弹出UAC弹窗。

其余和WSL1原理基本相同。

常见问题

scdaemon问题

这个一般是由于没有成功监听端口导致的,可以去掉nohup ** >/dev/null 2>&1 &看看报错信息,对应调试。

无反应

这个是监听成功,但是端口错误或者防火墙拦截导致的。

  1. 检查netsh.exe是否转发正确的端口。
  2. 检查Kelopatra是否正常识别到了你的硬件密钥。
  3. 如果都正常,重启Kelopatra,并打开一个新的bash
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇