跳到主要内容

2.2 Multiple Certificate Status Request Record (多证书状态请求记录)

支持证书状态协议 (如 OCSP) 的客户端可以向服务器发送 "status_request_v2" 扩展, 以便使用 TLS 握手来传输此类数据, 而不是通过单独的连接下载数据。使用此扩展时, "extension_data" 字段 (在 [RFC5246] 的第7.4.1.4节中定义) 必须包含 CertificateStatusRequestListV2, 其中:

struct {
CertificateStatusType status_type;
uint16 request_length; /* Length of request field in bytes */
select (status_type) {
case ocsp: OCSPStatusRequest;
case ocsp_multi: OCSPStatusRequest;
} request;
} CertificateStatusRequestItemV2;

enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;

struct {
ResponderID responder_id_list<0..2^16-1>;
Extensions request_extensions;
} OCSPStatusRequest;

opaque ResponderID<1..2^16-1>;
opaque Extensions<0..2^16-1>;

struct {
CertificateStatusRequestItemV2
certificate_status_req_list<1..2^16-1>;
} CertificateStatusRequestListV2;

在 OCSPStatusRequest (最初由 [RFC6066] 定义) 中, "ResponderID" 提供了客户端信任的 OCSP 响应者列表。长度为零的 "responder_id_list" 序列具有特殊含义, 即响应者对服务器是隐式已知的, 例如通过事先安排, 或由服务器使用的证书标识。"Extensions" 是 OCSP 请求扩展的 DER 编码 [X.690], 如果服务器支持转发 OCSP 请求扩展, 则必须在不修改的情况下转发此值。

"ResponderID" 和 "Extensions" 都是 [RFC6960] 中定义的 DER 编码的 ASN.1 类型。"Extensions" 从 [RFC5280] 导入。长度为零的 "request_extensions" 值表示没有扩展 (与 DER 编码的零长度 ASN.1 SEQUENCE 相对, 后者对于 "Extensions" 类型是无效的)。

使用 ResponderID 字段支持客户端选择响应者的服务器可以通过将客户端列表中的响应者 ID 值与已知 OCSP 响应者的 ResponderIDs 匹配来实现此选择, 可以使用值的二进制比较或哈希计算和比较方法。

在 "id-pkix-ocsp-nonce" OCSP 扩展的情况下, [RFC2560] 对其编码不清楚; 为了澄清, nonce 必须是 DER 编码的 OCTET STRING, 它被封装为另一个 OCTET STRING (请注意, 基于现有 OCSP 客户端的实现需要检查是否符合此要求)。这已在 [RFC6960] 中得到澄清。

CertificateStatusRequestItemV2 条目列表中的项目根据客户端的偏好排序 (最喜欢的选择在前)。

接收包含 "status_request_v2" 扩展的 client hello 的服务器可以向客户端返回合适的证书状态响应消息以及服务器的证书消息。如果请求了 OCSP, 则应该在选择 OCSP 响应者时使用扩展中包含的信息, 并且应该在 OCSP 请求中包含 request_extensions。

服务器通过在 "Certificate" 消息 ([RFC5246] 的第7.4.2节) 之后 (以及任何 "ServerKeyExchange" 或 "CertificateRequest" 消息之前) 立即发送 "CertificateStatus" 消息 (最初由 [RFC6066] 定义) 来返回证书状态响应以及其证书。如果服务器响应 "status_request_v2" 请求返回 "CertificateStatus" 消息, 则服务器必须在扩展服务器 hello 中包含类型为 "status_request_v2" 且 "extension_data" 为空的扩展。

"CertificateStatus" 消息使用握手消息类型 "certificate_status" (在 [RFC6066] 中定义) 传递, 如下所示 (从 [RFC6066] 中的定义更新):

struct {
CertificateStatusType status_type;
select (status_type) {
case ocsp: OCSPResponse;
case ocsp_multi: OCSPResponseList;
} response;
} CertificateStatus;

opaque OCSPResponse<0..2^24-1>;

struct {
OCSPResponse ocsp_response_list<1..2^24-1>;
} OCSPResponseList;

"OCSPResponse" 元素 (最初由 [RFC6066] 定义) 包含完整的、DER 编码的 OCSP 响应 (使用 [RFC6960] 中定义的 ASN.1 [X.680] 类型 OCSPResponse)。对于 status_type "ocsp", 只能发送一个长度至少为一个字节的 OCSP 响应。

"ocsp_response_list" 包含如上所述的 "OCSPResponse" 元素列表, 每个元素包含服务器 Certificate TLS 握手消息中相应匹配证书的 OCSP 响应。也就是说, 第一个条目是 Certificate 列表中第一个证书的 OCSP 响应, 第二个条目是第二个证书的响应, 依此类推。列表可以包含比 Certificate 握手消息中的证书少的 OCSP 响应, 但响应数量绝对不能超过列表中的证书数量。如果服务器没有存储该特定证书的 OCSP 响应, 列表的单个元素可以具有0 (零) 字节的长度, 在这种情况下, 客户端必须表现得就像未收到该特定证书的响应一样。如果客户端收到的 "ocsp_response_list" 不包含已完成证书链中一个或多个证书的响应, 则客户端应该尝试使用替代检索方法验证证书, 例如下载相关的 CRL; 在这种情况下, OCSP 应该仅用于最终实体证书, 而不是中间 CA 证书, 原因如上所述。

请注意, 即使服务器在 client hello 消息中收到了 "status_request_v2" 扩展并在 server hello 消息中发送了 "status_request_v2" 扩展, 服务器也可以选择不发送 "CertificateStatus" 消息。此外, 请注意, 除非服务器在 client hello 消息中收到 "status_request" 或 "status_request_v2" 扩展并在 server hello 消息中发送了相应的 "status_request" 或 "status_request_v2" 扩展, 否则服务器绝对不能发送 "CertificateStatus" 消息。

请求 OCSP 响应并在 "CertificateStatus" 消息中接收一个或多个 OCSP 响应的客户端必须检查 OCSP 响应, 如果响应是 "revoked" (已吊销) 状态或其他不可接受的响应 (由客户端策略确定), 则必须使用 bad_certificate_status_response(113) 警报中止握手。此警报始终是致命的。

如果从服务器收到的 OCSP 响应没有产生明确的 "good" (良好) 或 "revoked" (已吊销) 状态, 则它是不确定的。在这种情况下, TLS 客户端可以通过其他方式检查服务器证书的有效性, 例如, 通过直接查询证书颁发者。如果此类处理仍然导致不确定的响应, 则使用 TLS 连接的应用程序必须决定是否关闭连接。请注意, 如果没有来自应用程序的信息, 通用 TLS 客户端代码无法决定此问题。如果应用程序不提供任何此类信息, 则客户端必须中止连接, 因为服务器证书尚未得到充分验证。

应用程序可能希望继续的一个示例是 EAP-TLS (可扩展身份验证协议 - TLS), 其中应用程序可以在获得网络访问后使用另一种机制检查证书的状态。在这种情况下, 应用程序可以让客户端继续握手, 但在完全验证服务器证书之前, 绝对不能泄露用户名和密码。