无法验证 JWT 的 ECCP256 签名

问题描述 投票:0回答:1

我正在尝试使用嵌入在 Yubikey5 中的私钥 (ECCP256) 签署 JWT。

请注意,ECCP384 也不工作。

但是,签名验证不起作用(我正在 jwt.io 上尝试)

如果我使用 openssl 检查签名,则签名有效(并且我正在签署正确的数据,即 base64url(header)+"."+base64url(data) :

$ openssl dgst -sha256 -verify pubkey.pem -signature data.sig data.jwt 
Verified OK

我的脚本是:

echo -n '{"alg":"ES256","typ":"JWT"}' | base64  | tr -d "\n" | tr '+/' '-_' | tr -d '='  > token.jwt
printf  "." >> token.jwt


cat data.json | base64 | tr -d "\n" | tr '+/' '-_' | tr -d '='  >> token.jwt

echo "Generating signature ..."
yubico-piv-tool -a verify-pin --sign -s 9c -H SHA256 -A ECCP256 -i token.jwt -o data.sig

cp token.jwt data.jwt #this is just to check that i signed the right data
printf "." >> token.jwt
echo "Generating signed JWT ..."
cat data.sig | base64 | tr -d '\n=' | tr -- '+/' '-_' >> token.jwt

还有一个输出示例:

Enter PIN: 
Successfully verified PIN.
Signature successful!
Generating signed JWT ...
OK. Final token (stored in token.jwt) is : 
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJpYXQiOiAxNTE2MjM5MDIyCn0K.MEUCIGI9uVtz_r14rgJw19YdPR5sNbezKB3vOa3bApcFWJg2AiEAzf9ITwL-6fsapZt0pBzNYA5zaHBcmjP-HtCOA5uo870

我做错了什么吗?请注意,使用 RSA 2048 密钥的完全相同的脚本正在运行 (RS256)。

注意:使用 openssl 生成密钥对于 jwt 验证也不起作用(尽管签名由 OpenSSL 验证)

$ openssl ecparam -genkey -name prime256v1 -noout -out private.pem
$ openssl ec -in private.pem -pubout -out public.pem
$ echo -n '{"alg":"ES256","typ":"JWT"}' | base64  | tr -d "\n" | tr '+/' '-_' | tr -d '='  > token.jwt
$ echo -n "." >> token.jwt
$ cat ../data.json | base64 | tr -d "\n" | tr '+/' '-_' | tr -d '='  >> token.jwt
$ openssl dgst -sha256 -sign private.pem token.jwt > signature.bin
$ openssl dgst -sha256 -verify public.pem -signature signature.bin token.jwt
Verified OK
$ echo -n "." >> token.jwt
$ cat signature.bin | base64 | tr -d '\n=' | tr -- '+/' '-_' >> token.jwt
$ cat token.jwt 
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJpYXQiOiAxNTE2MjM5MDIyCn0K.MEUCIHY5OUbyovQX4jXFQVqF0ZIpoIBBjhQ6KMwnjHpp66JMAiEApIK2YspuRTXkzquunG-385QMFSACOKeKuQDGZC2mZcM
bash jwt cryptography digital-signature yubikey
1个回答
0
投票

openssl 和 yubico-piv 工具都会生成封装在 ASN.1 序列中的签名。例如,以下是使用 p256 曲线的 ECDSA 签名:

$ openssl dgst -sha256 -sign key.pem datatosign | openssl asn1parse -inform der
    0:d=0  hl=2 l=  69 cons: SEQUENCE          
    2:d=1  hl=2 l=  33 prim: INTEGER           :8F023B4A83817C6214533892D4F89E7DE2B81B0174A2F28F927E33B997A90ECA
   37:d=1  hl=2 l=  32 prim: INTEGER           :239D8BD1EA84C97A96F62634CDA56FF4A9CADA6663F84773620C80C8A62E2A37

JWT 然而使用原始签名。在上面的示例中,这意味着它应该只包含 (r,s) 整数对。要解决此问题,您只需将二进制整数连接到单个文件中(在本例中包含 64 字节)。

解析 ASN.1 结构有点棘手,因为不同的整数值的编码有所不同,但一个简单的技巧是使用 openssl 来实现此目的:

cat signature.der | openssl asn1parse -inform der | egrep -o '[A-F0-9]{64}' | xxd -r -p > signature.bin 

有关使用 YubiKey 签署 JWT 的完整示例,请参阅 这个要点。

© www.soinside.com 2019 - 2024. All rights reserved.