SSL/TLS无证书

9
我正在开发一个宠物项目,最终将允许进行安全文件传输(除此之外还有更多内容,但不是特别相关)。我想使用OpenSSL库,因为它似乎是最完整的免费加密库(我需要基本对称加密和哈希的支持,以及SSL/TLS)。
我希望实现类似于SSH的安全方案。基本上,用户将使用TLSv1(SSLv3.1)连接到我的计算机。我希望无论安全性如何,连接都能成功。然后,我想能够检查用户使用的公钥(不是整个证书)。该密钥将与已知的公钥进行比较,如果匹配,则允许用户访问某些命令。如果不匹配,用户将有选择使用连接来申请将其公钥添加到我的集合中,但除此之外将无法访问我的服务。
我在这里没有任何特殊需求证书。如果我可以跳过所有证书细节并仅使用原始加密密钥,那么这将更加简单。这是因为此模型遵循信任网络模型,而不是大多数SSL/TLS连接使用的分层模型,因此我不需要任何CA或签名证书。
不幸的是,大多数OpenSSL文档都不存在。我找到的所有相关文章似乎都在设置“标准”SSL/TLS连接,其中服务器的证书一直验证到一组根证书。这可能很有用,但我很难弄清楚如何启动这些非传统的SSL连接。
有人能建议任何文章或文档,帮助我找出如何完成这个任务吗?
(使用OpenSSL并不是必须的,如果它提供更好的方法来实现此目标以及哈希[SHA-512]和对称加密[AES],我可以切换到另一个库。我旨在针对Linux,但如果最终产品可移植到Windows,那将是很好的,这样我的朋友也可以使用它。)

1
将公钥与公钥列表进行比较,本质上是使用密码,这会破坏https和ssl的整个PKI性质。如果您控制客户端和服务器软件(因此可以配置信任关系),则创建和使用自签名证书的建议是一个好主意。 - Adam Liss
1
@AdamLiss,不,这和密码不同:用户从未必须发送私钥,而用户必须发送密码。(并且在列表中比较自签名证书与比较其公钥几乎相同。) - Bruno
@Ethan:你的方案问题在于公钥是公开的,也就是说,你不能使用自己的公钥来证明身份,因为它被认为是任何人都可以获得的。验证用户身份的正确方法是要求他使用自己的私钥加密一些已知数据;然后你使用他的公钥来解密。这正是使用PKI进行数字签名的方式。 - Adam Liss
@Adam,但这就是整个问题所在。当他们使用公钥建立SSL/TLS连接时,握手的一部分是使用公钥加密一些信息,以便另一端的节点使用其私钥进行解密。因此,身份验证的要求是(1)您必须拥有与我的数据库中匹配的公钥,(2)您必须证明您拥有与您的公钥相对应的私钥。 - Ethan
@AdamLiss,我没有感到困惑。公钥证书绑定了公钥、标识符和其他属性(例如用途)。PKI 定义了如何验证证书(即信任链如何工作)+如何解释某些属性。CertificateVerify TLS 消息与此无关。它是客户端使用私钥对所有握手消息(包括客户端证书)的串联进行签名。它必须使用客户端证书公钥进行验证,就这样。服务器是否希望信任此证书的内容是正交的(通常通过 PKI 完成)。 - Bruno
显示剩余8条评论
2个回答

4
为了补充Eugene的答案(我本来想把这个作为评论,但是有点长)...
FOAF+SSL项目(后来更名为WebID)中做过这种事情,坚持使用X.509证书使得实现更加容易,因为大多数SSL/TLS堆栈都是以此为设计思路(它们的API也反映了这一点)。
上次我检查FOAF+SSL时,传统的PKI检查仍然适用于客户端检查服务器证书。另一个选择类似于SSH,即第一次遇到时接受公钥/证书,并在其更改时警告用户。无论如何,这基本上就是SSH的工作方式(特别是,我猜第一次看到它时很少有人会在带外检查密钥的指纹)。
考虑仅客户端证书的使用(尽管其中一些内容也可以类似地应用于服务器证书):
  • 大多数服务器库似乎都能处理X.509证书,但可以更改它们的验证方式(例如Java中的X509TrustManager)。
  • 尽管在进行其他验证之前,您无法信任客户端证书所说的任何内容,但能够嵌入一些额外信息(例如主题DN或主题备用名称以查看用户声称的身份)可以帮助(a)用户组织其证书和(b)为验证器提供提示以了解要查找什么。裸公钥可能很难管理。
  • 许多现有的客户端工具(特别是浏览器)在执行SSL/TLS客户端身份验证时使用X.509证书。不需要做太多工作即可配置客户端使用自签名的X.509证书(而不是来自PKI的证书)。 (几乎没有支持TLS的OpenPGP工具,我不确定是否有任何工具能够将其用作客户端证书的形式。)
  • 由于您无法在没有外部检查的情况下信任证书,因此无论证书是否自签名(即发行者和主题是否相同),都无关紧要,至少假设用户不会向您发送不同意的证书(因此无需通过自己的密钥密封)。这样做的一个后果是,您可以很容易地构建一个用于发放证书的服务。例如,在浏览器中生成密钥对对于不想使用opensslkeytool命令的用户非常方便。 这里是一个示例服务,将发出带有用户所需SAN的证书(如果您与FOAF+SSL/WebID项目联系,可能会有更新的版本)。此类服务使用的任何私钥或发行者名称都几乎无关紧要,但由于浏览器围绕传统PKI设计,因此难以使用真正的自签名证书。

在请求特定客户端证书时也存在问题。TLS 1.1规范明确允许空的认证机构(请参见RFC 4346),而TLS 1.0则对此保持沉默。实际上,即使使用TLS 1.0,大多数客户端工具似乎都可以接受空列表(它们只会提供更多选择)。如果您希望系统中的证书易于识别,即使这些证书在实践中没有使用相同的私钥进行签名(因为您会忽略签名),您可以为所有这些证书使用相同的颁发者DN。


1
我的想法是生成一个邀请码并将该代码提供给朋友。除了代码之外,我还会输入一些关于我的新朋友的详细信息(特别是他们所在的地址,比如ethan.no-ip.org)。当他们发送“申请”时,他们使用邀请码,并可以发送消息。程序将检查邀请是否正确以及我输入的地址是否解析为创建申请时的原始地址。我还可以让您手动检查消息。这就是验证新“朋友”的方法。 - Ethan

2

使用自签名证书 - 这与“原始”密钥相同,但更易于管理(有关如何在openssl中接受或不接受自签名证书,请参见此问题)。


2
那么答案是“没有不使用证书的简单方法。 使用自签名证书更容易。”?我猜可以这样做。但我仍然可以跳过加载任何根证书,对吗?我想一个显而易见的后续问题是:我是否可以强制 OpenSSL 接受自签名证书? - Ethan
@Ethan,仅限制访问自签名证书(并拒绝其他证书)是没有意义的。如果您愿意接受任何自签名证书,那么您可能会接受任何东西,因为您将无法仅使用证书检查颁发者DN是否是他们所说的那样,无论颁发者DN = 主题DN是否变得不相关。 - Bruno
@Ethan 一般来说,SSL支持使用OpenPGP密钥或预共享密钥进行身份验证。但是这些都不适合。至于仅接受自签名证书-您可以动态控制信任什么,我猜在其他检查中,OpenSSL应该让您检查证书是否为自签名(其颁发者和主题字段必须相同)。 - Eugene Mayevski 'Callback
@Bruno,如果我只是在忽略证书的其余部分并仅使用公钥,那么这就有道理了。 - Ethan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接