是否可以使用 ssh 密钥签署文件?

Tom*_*son 41 ssh digital-signature

我使用 SSH(准确地说是 Linux 上的 OpenSSH 5.5p1)。我有一把钥匙,上面有密码。我将它用于通常登录计算机的东西。

我也可以用它来签署文件吗?

据我了解,SSH 密钥是一个 RSA(或 DSA)密钥,在 SSH 登录过程中,它用于对发送到服务器的消息进行签名。所以在原则上和实践中,它可以用于签署事物——事实上,这是它的唯一目的。

但据我所知,没有办法使用密钥对任意文件进行签名(就像使用 PGP 时那样)。有没有办法做到这一点?

Tom*_*son 28

单独使用 OpenSSH 工具可能无法做到这一点。

但是使用 OpenSSL 工具可以很容易地完成。事实上,至少有两种方法可以做到。在下面的示例中,~/.ssh/id_rsa是您的私钥。

一种方法是使用dgst

openssl dgst -sign ~/.ssh/id_rsa some-file
Run Code Online (Sandbox Code Playgroud)

另一种是使用pkeyutl

openssl pkeyutl -sign -inkey ~/.ssh/id_rsa -in some-file
Run Code Online (Sandbox Code Playgroud)

这两者都将二进制签名写入标准输出。DGST需要一个-hex选项将打印文本表示,有关签名的形式的一些细节。pkeyutl采用了-hexdump一个不太有用的选项。两者都将接受 RSA 和 DSA 密钥。我不知道输出的格式是什么。这两个命令产生不同的格式。我的印象是pkeyutl被认为比dgst更现代。

要验证这些签名:

openssl dgst -verify $PUBLIC_KEY_FILE -signature signature-file some-file
Run Code Online (Sandbox Code Playgroud)

和:

openssl pkeyutl -verify -inkey $PUBLIC_KEY_FILE -sigfile signature-file -in some-file
Run Code Online (Sandbox Code Playgroud)

这里的问题是$PUBLIC_KEY_FILE。OpenSSL 无法读取 OpenSSH 的公钥格式,因此您不能只使用id_rsa.pub. 你有几个选择,都不理想。

如果您有 5.6 或更高版本的 OpenSSH,您显然可以这样做:

ssh-keygen -e -f ~/.ssh/id_rsa.pub -m pem
Run Code Online (Sandbox Code Playgroud)

它将公钥以 PEM 格式写入标准输出,OpenSSL 可以读取。

如果您有私钥,并且它是 RSA 密钥,那么您可以从中提取公钥(我假设 PEM 编码的私钥文件包含公钥的副本,因为无法导出公钥来自私钥本身),并使用它:

openssl rsa -in ~/.ssh/id_rsa -pubout
Run Code Online (Sandbox Code Playgroud)

我不知道是否有等效的 DSA。请注意,此方法需要私钥所有者的一些合作,他必须提取公钥并将其发送给潜在的验证者。

最后,您可以使用一个名为 Lars 的人编写的 Python 程序将公钥从 OpenSSH 转换为 OpenSSL 格式。

  • 我只想指出“不可能从私钥本身导出公钥”是不正确的。在实践中(即在所有实际使用的密码系统中),大多数时候公钥很容易从私钥中导出。 (2认同)

ste*_*n.z 13

@Tom 的回答帮助我入门,但没有开箱即用。

这些命令将用于:

  • OpenSSL 1.0.1 2012 年 3 月 14 日
  • OpenSSH_5.9p1

使用 pkeyutl

# openssl pkeyutl -sign -inkey ~/.ssh/id_sample -in $1 > $1.sig
# ssh-keygen -e -f ~/.ssh/id_sample.pub -m PKCS8 > pub
# openssl pkeyutl -verify -pubin -inkey pub -in $1 -sigfile $1.sig
Signature Verified Successfully
Run Code Online (Sandbox Code Playgroud)

使用 dgst

# openssl dgst -sign ~/.ssh/id_sample $1 > $1.sig
# ssh-keygen -e -f ~/.ssh/id_sample.pub -m PKCS8 > pub
# openssl dgst -verify pub -signature $1.sig $1
Verified OK
Run Code Online (Sandbox Code Playgroud)

pkeyutl 版本只能对小文件进行签名。而 dgst 可以对任意大的文件进行签名,因为它在对结果签名之前需要一个摘要。


jvp*_*nis 11

我偶然发现了这个旧帖子,正在寻找同样的东西。事实证明,ssh-keygen现在 OpenSSH 工具可以直接使用现有的 SSH 密钥生成和验证签名。这已在OpenSSH 8.1 中引入(于 2019-10-09 发布)中。

TL; 博士

使用ssh-keygen签名和验证签名:

echo "Hello, World!" | ssh-keygen -Y sign -n file -f id_rsa > content.txt.sig
echo "Hello, World!" | ssh-keygen -Y check-novalidate -n file -f id_rsa.pub -s content.txt.sig
Run Code Online (Sandbox Code Playgroud)

ssh-keygen 的参数

因为我没有找到ssh-keygen手册页特别有用(还),这里概述了一些有用的命令及其对内容进行签名所需的参数。

签约内容:

ssh-keygen 
-Y sign        # The 'sign' signature operation
-n <namespace> # Signature namespace (e.g. file or email)
-f <file>      # Path to the private key to sign the content with
<files>        # Paths to one or more files you want to sign (optional, by default reads from stdin)
Run Code Online (Sandbox Code Playgroud)

检查签名内容的签名:

ssh-keygen 
-Y check-novalidate # The 'check' signature operation
-n <namespace>      # Namespace the signature was generated in
-f <file>           # Path to the public key to validate the signature with
-s <file>           # Path to the signature file
Run Code Online (Sandbox Code Playgroud)

检查签名并验证签名者是否有权对内容进行签名:

ssh-keygen 
-Y verify      # The 'verify' signature operation
-n <namespace> # Namespace the signature was generated in
-f <file>      # Path to the ALLOWED SIGNERS file
-s <file>      # Path to the signature file
-I <principal> # The expected identity principal used to generate the signature
Run Code Online (Sandbox Code Playgroud)

在 ALLOWED SIGNERS 文件中搜索适用于指定签名的任何主体:

ssh-keygen 
-Y find-principals # The 'find principals' signature operation
-f <file>          # Path to the ALLOWED SIGNERS file
-s <file>          # Path to the signature file
Run Code Online (Sandbox Code Playgroud)

显示您的密钥的主体(通常<username>@<hostname>从生成时开始):

ssh-keygen 
-l        # Print the key's fingerprint
-f <file> # Path to the public key 
Run Code Online (Sandbox Code Playgroud)

从证书颁发机构 (CA) SSH 密钥生成用户证书:

ssh-keygen 
-I <cert_id>    # The certificate identity
-s <file>       # Path to the CA's private key
-n <principals> # Identity principals allowed by the generated certificate
<files>         # Path to one or more public keys to generate a certificate for
Run Code Online (Sandbox Code Playgroud)

允许的签名者文件

此文件包含允许对内容进行签名的身份列表,因此用于确定签名是否来自授权来源。该格式类似于众所周知的authorized_keys文件,并在手册页的允许签名者部分中有更详细的描述。

<princpal>[,<principal>,..] [cert-authority] [namespaces="<namespace>[,<namespace>,..]"] <public-key>
Run Code Online (Sandbox Code Playgroud)

例子:

user1@server,user2@server ssh-rsa AAAAX1...
*@server cert-authority ssh-rsa AAAAX1...
Run Code Online (Sandbox Code Playgroud)

使用签名操作命令

生成签名并验证它的最简单方法:

# Generate a new SSH key
ssh-keygen -f id_rsa -N ''

# Create the original content to be signed
echo "Trust me, the author!" > content.txt

# Sign the content
cat content.txt | ssh-keygen -Y sign -n file -f id_rsa > content.txt.sig

# Check the signature of the content
cat content.txt | ssh-keygen -Y check-novalidate -f id_rsa.pub -n file -s content.txt.sig
Run Code Online (Sandbox Code Playgroud)

现在尝试检查包含无效内容的签名:

# Pretend the content has been tampered with by a malicious party
echo "Trust ME, the hacker!" > content-tampered.txt

# Check the signature of the content again (which will fail)
cat content-tampered.txt | ssh-keygen -Y check-novalidate -f id_rsa.pub -n file -s content.txt.sig
Run Code Online (Sandbox Code Playgroud)

请注意,签名已使用check-novalidate签名操作进行了验证。novalidate当您要验证签名是否与内容匹配时,这部分听起来有点吓人。但是,当此检查成功时,它意味着签名与原始内容匹配。您只是没有关于签名者是否被授权对内容进行签名的信息。

当您拥有信任并希望用于签署内容的公钥时,您可以使用 ALLOWED SIGNERS 文件:

# Export your key's principal
ssh-keygen -l -f id_rsa.pub | cut -d ' ' -f3 > identity

# Create an ALLOWED SIGNERS file
echo "$(cat identity) $(cat id_rsa.pub)" > allowed_signers

# Check signature and verify the signer 
cat content.txt | ssh-keygen -Y verify -f allowed_signers -I $(cat identity) -n file -s content.txt.sig
Run Code Online (Sandbox Code Playgroud)

正如您在上面的概述中可能已经看到的那样,OpenSSH 现在也能够签署其他 SSH 密钥。这意味着我们可以使用 SSH 密钥来充当证书颁发机构 (CA),这非常酷!

这允许您为签名做的只是在 ALLOWED SIGNERS 文件中指定 CA 的公钥,而所有由 CA 签名的 SSH 密钥都能够对有效内容进行签名:

# Generate a new CA key
ssh-keygen -f ca -C 'SSH Certificate Authority' -N ''

# Replace the ALLOWED SIGNERS file contents with just the CA's public key
echo "$(cat identity) cert-authority $(cat ca.pub)" > allowed_signers

# Sign your public key using the CA, creating a user certificate
ssh-keygen -I $(cat identity) -s ca -n $(cat identity) id_rsa

# Sign the content by specifying the user certificate (which uses the private key)
cat content.txt | ssh-keygen -Y sign -n file -f id_rsa-cert.pub > content.txt.sig

# Validate the signature using the CA's public key
cat content.txt | ssh-keygen -Y verify -f allowed_signers -I $(cat identity) -n file -s content.txt.sig
Run Code Online (Sandbox Code Playgroud)

现在我们有了一个 CA,我们还可以使用自定义的任意主体,因为它们嵌入在证书中

# Sign your public key using the CA, adding a custom principal
ssh-keygen -I $(cat identity) -s ca -n $(cat identity),trusted-authors id_rsa

# Replace the ALLOWED SIGNERS file contents, allowing only signatures generated by keys with the trusted-authors principal
echo "trusted-authors cert-authority $(cat ca.pub)" > allowed_signers

# Sign the content by specifying the user certificate 
cat content.txt | ssh-keygen -Y sign -n file -f id_rsa-cert.pub > content.txt.sig

# Validate the signature using the CA's public key and the expected custom principal
cat content.txt | ssh-keygen -Y verify -f allowed_signers -I trusted-authors -n file -s content.txt.sig
Run Code Online (Sandbox Code Playgroud)

结果文件

如果您按照上面的命令进行操作,您最终会在目录中看到这些文件:

allowed_signers      # List of principal(s) and key combinations authorized to sign the content 
ca                   # Private key of the Certificate Authority
ca.pub               # Public key of the Certificate Authority
content-tampered.txt # The content that got tampered with
content.txt          # The original content
content.txt.sig      # A signature of the original content
id_rsa               # Our private key - used to generate the signature
id_rsa-cert.pub      # Certificate signed by the CA - used to check and verify the signature
id_rsa.pub           # Our public key  - used to check the signature
identity             # Helper file which contains the identity principal of our private key
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你!

  • 这现在应该是最重要的评论,因为其他评论现在已经过时了。谢谢。 (3认同)