目前我正在尝试使用 socat 设置玩具 https 服务器,我正在执行以下操作:
正如这里所描述的:使用 SOCAT 的 OPENSSL 连接示例
cert() {
openssl genrsa -out $1.key 2048
openssl req -new -key $1.key -x509 -days 3653 -out $1.crt
cat $1.key $1.crt > $1.pem
}
$ cert server && cert client
$ openssl dhparam -out dhparams.pem 2048 # see [1]
$ cat dhparams.pem >> server.pem
Socat SSL – SSL 例程:SSL3_CHECK_CERT_AND_ALGORITHM:dh 密钥太小
然后在 1 号终端运行:
$ socat ssl-l:1443,reuseaddr,fork,cert=server.pem,cafile=client.crt,verify=1 exec:'uptime'
在#2 终端中我运行:
$ socat - ssl:localhost:1443,cert=client.pem,cafile=server.crt
一切都按预期进行,我得到了正常运行时间,但如果我这样做了
$ curl --cert client.pem --cacert server.crt https://localhost:1443
curl: (51) SSL: unable to obtain common name from peer certificate
它失败。
我承认我对 HTTPS 的理解有点不稳定,所以我有几个问题:
- 为什么会失败?
- 为什么我们需要将客户端证书传输到服务器?当我浏览网络时,这种情况不会发生,不是吗?
答案1
为什么会失败?
您显然遵循的说明部分不正确。
$ openssl req -new -key server.key -x509 -days 3653 -out server.crt
// enter fields... (may all be empty when cert is only used privately)
提示的字段req -new -x509
(至少对于“标准”上游配置文件)用作创建的证书(或不带 的 CSR -x509
)中的使用者名称。 (对于自签名证书,颁发者名称与主题名称相同,因此相同的数据也会出现在那里。)
对于 HTTPS 服务器,要确定连接已到达有效服务器而不是冒名顶替者,服务器的证书必须根据 rfc5280 有效(由受信任的 CA 等签名),并且必须将证书颁发给 URL 中指定的服务器:证书中主题名称中的通用名称字段必须与所需的服务器匹配,或者主题备用名称扩展(通常缩写为 SAN,也被 Microsoft 或受 Microsoft 影响的人称为 UCC)必须存在并包含一个这样做的条目。看RFC2818。这就是 OpenSSL 提示输入此字段的原因:
Common Name (e.g. server FQDN or YOUR name) []:
因为大多数人使用通过 FQDN 标识服务器的 URL,但也有例外。因此您需要用 回答该提示localhost
。官方认为 SAN 是首选,自 2000 年左右以来,所有“真正的”CA( Verisign Symantec Digicert、GoDaddy 等)都实施了 SAN ,但使用 OpenSSL 执行 SAN 需要做更多的工作。 Stack 上已经有很多关于 OpenSSL 中 SAN 的问题;如果你需要但找不到它们,我会从我的笔记中找出一些。一个例外是如果你想使用 Chrome/chromium:从几个月前开始需要该证书具有 SAN(具有正确的服务器名称)并且不再接受 subject.CN。对此也有疑问;同上。
注意 除 HTTPS 之外,基于 SSL/TLS 的协议可能有所不同,并且空主题名称可能确实没问题,例如 FTPS SNMPS LDAPS。
为什么我们需要将客户端证书传输到服务器?当我浏览网络时,这种情况不会发生,不是吗?
您真正指的是网络还是万维网?尽管 SSL/TLS 协议支持通过客户端证书进行客户端身份验证,但网络的安全 (HTTPS) 部分上很少有 Web 服务器使用此功能。大多数需要验证其客户端身份的 Web 服务器都使用 HTTP 级别的方法——例如Stack 提供的选项。这使他们能够控制 UI 并使其在所有浏览器中保持一致,并相应地提供说明、帮助和支持,而客户端证书的 UI 由每个浏览器或平台以不同的方式实现,并且通常需要一些技术技能或至少智力和耐心正确使用,大多数网站认为大多数用户不能或至少不会这样做。
少数确实使用客户端证书的 Web 服务器通常需要由公共 CA 和/或受信任的第三方(例如政府或银行)颁发的证书,或者有时需要由服务器本身运行或控制的 CA 颁发的证书。使用自签名客户端证书确实需要用户提前提供他们的证书 - 并且该提供过程必须非常安全,因为任何可以接受一次伪造证书的人都可以在多年内进行欺诈性连接。
OTOH,当您“拥有”两端时,服务器管理员可以轻松识别和信任客户端管理员,反之亦然。 AIUI OpenVPN 密钥交换使用此(具有自签名或 adhoc-CA 证书的 SSL/TLS)。
额外的答案:上述更改应该使连接的 TLS 层正常工作,但您的设置仍然无法作为 HTTPS 服务器工作,因为 的输出uptime
不是有效的 HTTP 响应。您需要生成 HTTP 标头的东西和内容,与 CGI“页面”在真实 Web 服务器(对于 HTTP 或 HTTPS)下的工作方式大致相同。
答案2
这通用名需要字段。可以通过参数指定-subj
:
$ openssl req -new -key $1.key -x509 -subj '/CN=localhost' -out $1.cert
此外,curl
还需要一个 HTTP 标头:
$ printf "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 5\r\n\r\nhello" | socat -dd openssl-listen:8080,cert=server.pem,verify=0 -