我需要为我使用 Boost Asio SSL
编写的程序编写一段代码。
我有一个由两个客户端组成的系统,它们相互连接。我要求他们进行相互身份验证,因此,在 handshake()
命令结束时,两个客户端都可以确定另一个客户端拥有他们提供的证书的私钥。
两个客户端都有一个context
对象,我们称它们为ctx1
和ctx2
,每个客户端都有一个公钥和一个私钥。
是否可以设置上下文对象,以便当我调用 socket.handshake()
时,客户端将执行双向身份验证。如果不是,实现我的目标的正确方法是什么?
最佳答案
看起来boost只是使用了OpenSSL接口(interface)。 我对 boost 了解不多,但我已经为 Perl 实现了很多 OpenSSL 内部机制,并在阅读了 boost 源代码的相关部分后得出以下结论:
要与 OpenSSL 进行相互身份验证,您必须在客户端使用 SSL_VERIFY_PEER
,在服务器端使用 SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT
。如果您在服务器端仅使用 SSL_VERIFY_PEER
,它只会向客户端发送证书请求,但如果客户端未发回证书,则静默接受。
随着 boost ,这可能是:
ctx.set_verify_mode(ssl::verify_peer); // client side
ctx.set_verify_mode(ssl::verify_peer|ssl::verify_fail_if_no_peer_cert); // server side
如果您以这种方式设置 verify_mode,它将根据配置的受信任 CA 验证证书(使用 ctx.load_verify_file
或 ctx.load_verify_path
设置)。
如果您对签署证书的 CA(即您自己的 CA)拥有完全控制权,那么您接受由该 CA 签署的任何证书可能就足够了。但是,如果您使用的 CA 也签署了您不想接受的证书,就像公共(public) CA 的典型情况一样,您还需要验证证书的内容。如何执行此操作的详细信息取决于您的协议(protocol),但对于常见的 Internet 协议(protocol)(如 HTTP 或 SMTP),这涉及检查证书的 commonName 和/或 subjectAltNames。通配符处理等细节因协议(protocol)而异。
Boost 提供 rfc2818_verification以帮助您进行 HTTP 样式的验证,尽管从阅读代码我认为实现略有错误(接受多个通配符,允许 IDN 通配符 - 请参阅 RFC6125 了解要求)。
我不知道验证客户端证书的任何标准。通常只接受由特定(私有(private))CA 签名的任何证书。其他时候来自与特定电子邮件模式匹配的公共(public) CA 的证书。看起来 boost 在这种情况下对你帮助不大,所以你可能必须使用 sock.native_handle()
获取 OpenSSL SSL*
句柄,然后使用 OpenSSL 函数来提取证书 (SSL_get_peer_certificate
) 并检查证书的内容(各种 X509_*
函数)。
至少如果涉及公共(public) CA,您还应该检查证书的吊销状态。看起来 boost 没有提供 CRL(证书吊销列表)的直接接口(interface),因此您必须使用 ctx.native_handle()
和适当的 OpenSSL 函数(X509_STORE_add_crl
等) .使用 OCSP(在线状态撤销协议(protocol))要复杂得多,而且相关的 OpenSSL 函数大多没有记录,这意味着您必须阅读 OpenSSL 源代码才能使用它们:(
关于c++ - boost asio SSL双向身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25342971/