SSL 客户端证书认证

信息安全 tls 证书 公钥基础设施
2021-08-18 01:52:03

是否可以制作一个仅使用公钥和私钥进行客户端证书身份验证的程序(我没有生成任何证书,我只有公钥和私钥)。

简单地说,我想通过客户端证书身份验证在服务器上进行身份验证。但是很难以编程方式制作客户端证书。

我想只使用公钥和私钥进行客户端证书身份验证(我只有公钥和私钥,没有证书)。

是否可以发送服务器公钥而不是客户端证书进行客户端证书身份验证?

4个回答

证书只是带有一些附加上下文的公钥。密钥的名称、签名、使用指南等。 SSL/TLS取决于该上下文。否则,您要连接的主机将不知道密钥是否真正属于您。SSL 信任机制建立在显式信任证书的概念之上,然后是它们签署的隐式信任证书。

但是,如果您不使用 SSL 或 TLS,那么在没有它的情况下仍然可以进行加密,但信任必须以不同的方式发生。SSH 就是一个很好的例子:SSH 仍然使用公钥和私钥,但由于没有签名层次结构,证书提供的附加信息将无用,因此密钥是裸露的。相反,客户端在第一次连接时询问您是否信任服务器的公钥,然后每次都检查公钥是否与上次看到的相匹配。 之所以会发生这种情况,是因为 SSH 不使用 SSL 或 TLS 进行加密。

但是,如果您使用 SSL 协议,则该协议规定公钥必须与证书的附加上下文一起提供。也就是说,证书是公共密钥必须放入的容器,SSL 才能使用它。

如果您有私钥,使用 OpenSSL 等工具创建自签名证书很简单。

SSL/TLS支持使用证书的客户端身份验证。内部真正发生的是:

  • 服务器通过CertificateRequest消息请求“客户端证书”
  • 客户端将其证书作为Certificate消息发送,并且还计算握手中所有先前消息的签名(使用其私钥);签名作为CertificateVerify消息发送。
  • 服务器以某种方式获取客户端公钥(通常通过将客户端证书解码为X.509证书,以 X.509 方式对其进行验证,然后从中提取公钥)并使用它来验证来自客户端的签名.

但是,在协议本身中,证书作为不透明的字节块进行交换;每个“证书”都带有一个指定其长度的 3 字节标头。因此,如果您同时控制服务器和客户端代码,那么完全由您决定如何解释这些字节块。您无需发送X.509 证书如果您愿意,您可以发送一条空消息。

重点仍然存在:

  • 为了使身份验证有意义,服务器必须在一定程度上知道客户端公钥。签名表明客户端控制着私钥,但这只有在对应的公钥明确地附加到已知的客户端身份时才有用。

  • 密钥对必须是适合签名的类型(即 RSA 或 DSA,而不是 Diffie-Hellman)。

现有的 SSL 实现可能会坚持至少尊重 X.509 格式,在这种情况下,您必须将您的公钥包装在某种自签名的 X.509 证书中,这对于某些库(如OpenSSL )以编程方式相对容易。

有一个用 OpenPGP 公钥替换 SSL 中的 X.509 证书的标准,展示了 SSL 固有的格式灵活性。

(这是基于我对 SO 上同一个问题的回答。通常最好只在一个 SE 网站上提问。)

TLS 协议只允许交换证书,不允许交换原始公钥。甚至“PGP 密钥”(如果您想用OpenPGP 替换 X.509 以在 TLS 中进行身份验证,支持的程度要低得多)实际上是证书(它们是公钥和一组标识符和属性的签名组合) .

正如 Thomas 所说,您可以定义自己的证书类型并将它们设为普通公钥(尽管我不确定它们在技术上仍然可以称为“证书”)。

从实际的角度来看,您应该能够使用现有的 SSL/TLS 堆栈来实现您所需要的,并谨慎地调整它们处理验证 X.509 证书的方式事实上,大多数 SSL/TLS 堆栈通过其 API 公开 X.509 证书的验证,但很少允许其他类型的证书(例如 OpenPGP)或允许您轻松自定义其代码。非 X.509 证书的定制可能非常困难,如果您是 SSL/TLS 实施的新手,可能会导致额外的错误,并且在实践中也难以部署,因为所有潜在客户也需要支持您的定制.

您可以使用自签名客户端 X.509 证书执行客户端身份验证并依赖其公钥(但您需要根据您的服务器已经知道的内容验证此公钥,例如已知列表)。您需要首先了解实现此功能的安全隐患。这与自签名服务器证书的问题并不完全相同。(我建议保留更传统的方法来验证服务器证书。)

您可以让客户端发送自签名证书(可能使用有关服务器公布的 CA 列表的某些技巧)并在 TLS 堆栈中或稍后在应用程序中执行验证。

请注意,许多应用程序容器(例如 Java 中的 Tomcat/Jetty)期望 SSL/TLS 层来验证客户端证书。因此,如果您跳过那里的身份验证(并希望稍后在容器内或作为应用程序的一部分进行),许多应用程序框架将会混淆。在执行任何需要在应用程序中进行身份验证的操作之前,您需要非常小心地确保在某处实际执行了身份验证。

例如,在 Tomcat/Jetty 中有一个允许任何客户端证书通过的信任管理器是可以的,但您不能依赖javax.servlet.request.X509Certificate请求属性已经以任何方式验证(大多数框架本来会期望)。您需要在应用程序中实现一些验证逻辑:例如,在任何经过​​身份验证的功能之前有一个过滤器,该过滤器将此客户端证书中的公钥与您已知的公钥列表进行比较(或者您希望将公钥与标识符)。或者,您也可以在自定义信任管理器(在 Java 中)中执行此验证,这将需要在应用程序中进行较少的工作。

您可以在 Apache Httpd + PHP 设置(例如)中执行类似的操作,使用SSLVerifyClient optional_no_ca. 同样,您的 PHP 应用程序不能依赖已验证的证书,因此您也必须在那里实现验证。

除非您了解您获得的证书信息在哪个阶段得到了验证,否则请勿执行任何此类操作。

除了我们亲爱的朋友,泰勒

您应该了解 OpenSSL linux 命令并具有良好的 PHP 或 perl 编程技能。(特别是 PHP)这里有一些很好的指南:1- http://www.php.net/manual/en/book.openssl.php 和 2-openssl。org 你必须对 openssl 命令及其功能有深入的了解。

最后:(您的问题)可以发送服务器公钥而不是客户端证书进行客户端证书身份验证吗?不,因为您可能会忘记 TLS 握手协议,它逐步显示客户端-服务器身份验证和密钥交换。 http://msdn.microsoft.com/en-us/library/windows/desktop/aa380513%28v=vs.85%29.aspx