OpenSSL 入门:密码学基础知识( 二 )

可以从命令行编译和执行该程序(请注意 -lssl 和 -lcrypto 中的小写字母 L):
gcc -o client client.c -lssl -lcrypto该程序尝试打开与网站 www.google.com 的安全连接 。在与 Google Web 服务器的 TLS 握手过程中,client 程序会收到一个或多个数字证书,该程序会尝试对其进行验证(但在我的系统上失败了) 。尽管如此,client 程序仍继续通过安全通道获取 Google 主页 。该程序取决于前面提到的安全工件,尽管在上述代码中只着重突出了数字证书 。但其它工件仍在幕后发挥作用,稍后将对它们进行详细说明 。
通常,打开 HTTP(非安全)通道的 C 或 C++ 的客户端程序将使用诸如文件描述符或网络套接字之类的结构,它们是两个进程(例如,这个 client 程序和 Google Web 服务器)之间连接的端点 。另一方面,文件描述符是一个非负整数值,用于在程序中标识该程序打开的任何文件类的结构 。这样的程序还将使用一种结构来指定有关 Web 服务器地址的详细信息 。
这些相对较低级别的结构不会出现在客户端程序中,因为 OpenSSL 库会将套接字基础设施和地址规范等封装在更高层面的安全结构中 。其结果是一个简单的 API 。下面首先看一下 client 程序示例中的安全性详细信息 。

  • 该程序首先加载相关的 OpenSSL 库,我的函数 init_ssl 中对 OpenSSL 进行了两次调用:SSL_load_error_strings();
    SSL_library_init();
  • 下一个初始化步骤尝试获取安全上下文,这是建立和维护通往 Web 服务器的安全通道所需的信息框架 。如对 OpenSSL 库函数的调用所示,在示例中使用了 TLS 1.2:const SSL_METHOD* method = TLSv1_2_client_method(); /* TLS 1.2 */
    如果调用成功,则将 method 指针被传递给库函数,该函数创建类型为 SSL_CTX 的上下文:SSL_CTX* ctx = SSL_CTX_new(method);
    client 程序会检查每个关键的库调用的错误,如果其中一个调用失败,则程序终止 。
  • 现在还有另外两个 OpenSSL 工件也在发挥作用:SSL 类型的安全会话,从头到尾管理安全连接;以及类型为 BIO( 基本输入/输出(Basic Input/Output))的安全流,用于与 Web 服务器进行通信 。BIO 流是通过以下调用生成的:
    BIO* bio = BIO_new_ssl_connect(ctx);
    请注意,这个最重要的上下文是其参数 。BIO 类型是 C 语言中 FILE 类型的 OpenSSL 封装器 。此封装器可保护 client 程序与 Google 的网络服务器之间的输入和输出流的安全 。
  • 有了 SSL_CTX 和 BIO,然后程序在 SSL 会话中将它们组合在一起 。三个库调用可以完成工作:
    BIO_get_ssl(bio, &ssl); /* 会话 */
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* 鲁棒性 */
    BIO_set_conn_hostname(bio, name); /* 准备连接 */
    安全连接本身是通过以下调用建立的:
    BIO_do_connect(bio);
    如果最后一个调用不成功,则 client 程序终止;否则,该连接已准备就绪,可以支持 client 程序与 Google Web 服务器之间的机密对话 。
在与 Web 服务器握手期间,client 程序会接收一个或多个数字证书,以认证服务器的身份 。但是,client 程序不会发送自己的证书,这意味着这个身份验证是单向的 。(Web 服务器通常配置为不需要客户端证书)尽管对 Web 服务器证书的验证失败,但 client 程序仍通过了连接到 Web 服务器的安全通道继续获取 Google 主页 。
为什么验证 Google 证书的尝试会失败?典型的 OpenSSL 安装目录为 /etc/ssl/certs,其中包含 ca-certificates.crt 文件 。该目录和文件包含着 OpenSSL 自带的数字证书,以此构成 信任库(truststore) 。可以根据需要更新信任库,尤其是可以包括新信任的证书,并删除不再受信任的证书 。
client 程序从 Google Web 服务器收到了三个证书,但是我的计算机上的 OpenSSL 信任库并不包含完全匹配的证书 。如目前所写,client 程序不会通过例如验证 Google 证书上的数字签名(一个用来证明该证书的签名)来解决此问题 。如果该签名是受信任的,则包含该签名的证书也应受信任 。尽管如此,client 程序仍继续获取页面,然后打印出 Google 的主页 。下一节将更详细地介绍这些 。
客户端程序中隐藏的安全性让我们从客户端示例中可见的安全工件(数字证书)开始,然后考虑其他安全工件如何与之相关 。数字证书的主要格式标准是 X509,生产级的证书由诸如 Verisign 的 证书颁发机构(Certificate Authority)(CA)颁发 。
数字证书中包含各种信息(例如,激活日期和失效日期以及所有者的域名),也包括发行者的身份和数字签名(这是加密过的加密哈希值) 。证书还具有未加密的哈希值,用作其标识指纹 。


推荐阅读