Solaris 开发者安全性指南

在 GSS-API 中发送受保护的数据

在对等应用程序之间建立上下文之后,即可在发送消息之前对其进行保护。

建立上下文时使用的只是最基本的 GSS-API 保护:验证。根据基础安全机制,GSS-API 提供了另外两个保护级别:

gss_get_mic()gss_wrap() 之间的区别如下图所示:使用 gss_get_mic(),接受器可获取用于指示消息是否保持不变的标记;使用 gss_wrap(),接受器除了获取标记外还可获取经过加密的消息。

图 4–7 gss_get_mic()gss_wrap()

该图对 gss_get_mic 和 gss_wrap 函数进行比较。

要使用哪个函数取决于具体情况。由于 gss_wrap() 包括完整性服务,因此许多程序都使用 gss_wrap()。程序可以测试保密性服务的可用性,随后可以根据保密性服务的可用情况,以应用或不应用保密性的方式调用 gss_wrap()包装和发送消息即是一个示例。但是,由于无需展开使用 gss_get_mic() 的消息,因此所使用的 CPU 周期比 gss_wrap() 所使用的要少。所以,不需要保密性的程序可能会使用 gss_get_mic() 来保护消息。

使用 gss_get_mic() 标记消息

程序可以使用 gss_get_mic() 向消息添加加密 MIC。接收者可以通过调用 gss_verify_mic() 检查消息的 MIC。

gss_wrap() 相比,gss_get_mic() 会针对消息和 MIC 生成不同的输出,这意味着发送者应用程序必须既能发送消息又能发送随附的 MIC。更重要的是,接收者必须能够区分消息和 MIC。以下方法可确保对消息和 MIC 进行正确的处理:

如果 gss_get_mic() 成功完成,则将返回 GSS_S_COMPLETE。如果指定的 QOP 无效,则将返回 GSS_S_BAD_QOP。有关更多信息,请参见 gss_get_mic(3GSS)

使用 gss_wrap() 包装消息

可以使用 gss_wrap() 函数来包装消息。与 gss_get_mic() 一样,gss_wrap() 也提供了 MIC。如果基础机制允许使用所请求的保密性,则 gss_wrap() 也会对指定的消息进行加密。消息的接收者通过使用 gss_unwrap() 来展开消息。

gss_get_mic() 不同,gss_wrap() 会将消息和 MIC 一起包装到传出消息中。用于传送该包的函数只需调用一次。在另一端,可以使用 gss_unwrap() 提取消息。MIC 对于应用程序不可见。

如果消息已成功包装,则 gss_wrap() 将返回 GSS_S_COMPLETE。如果所请求的 QOP 无效,则将返回 GSS_S_BAD_QOP。有关 gss_wrap() 的示例,请参见包装和发送消息

在 GSS-API 中处理包装大小问题

使用 gss_wrap() 来包装消息会增加要发送的数据量。由于所保护的消息包需要适应指定的传输协议,因此 GSS-API 提供了 gss_wrap_size_limit() 函数。gss_wrap_size_limit() 用于计算可以包装的消息的最大大小,使其不至于因变得过大而不适用于该协议。应用程序可以在调用 gss_wrap() 之前截断超出该大小的消息。在实际包装消息之前,请始终检查包装大小限制。

包装大小的增加取决于以下两个因素:

缺省的 QOP 会因不同的 GSS-API 实现而异。因此,即使指定了缺省的 QOP,所包装消息的大小也会有所不同。下图说明了这种可能性:

该图显示选定的 QOP 如何影响消息大小。

无论是否应用了保密性,gss_wrap() 仍然会增加消息的大小。gss_wrap() 可将 MIC 嵌入到所传送的消息中。但是,对消息进行加密会进一步增加消息的大小。此过程如下图所示。

该图显示使用保密性会增加消息大小。

如果 gss_wrap_size_limit() 成功完成,则将返回 GSS_S_COMPLETE。如果指定的 QOP 无效,则将返回 GSS_S_BAD_QOP包装和发送消息中提供了一个说明如何使用 gss_wrap_size_limit() 返回原始消息最大大小的示例。

成功完成此调用并不一定保证 gss_wrap() 可以保护长度为 max-input-size 个字节的消息。能否保护消息取决于调用 gss_wrap() 时系统资源是否可用。有关更多信息,请参见 gss_wrap_size_limit(3GSS) 手册页。

在 GSS-API 中检测顺序问题

由于上下文启动器会向接受器传送顺序的数据包,因此某些机制允许上下文接受器检查顺序是否正确。这些检查包括数据包是否按正确的顺序到达以及是否存在不必要的数据包重复。请参见下图。接受器可以在检验数据包和展开数据包的过程中检查这两种情况。有关更多信息,请参见展开消息

图 4–8 消息重放和消息失序

该图显示了消息重复和消息失序的情况。

启动器可以使用 gss_init_sec_context() 来检查顺序,方法是通过 GSS_C_REPLAY_FLAGGSS_C_SEQUENCE_FLAGreq_flags 参数应用逻辑 OR

在 GSS-API 中确认消息传送

接收者展开或检验所传送的消息之后,会向发送者返回确认信息,这意味着会发回该消息的 MIC。请考虑以下情况:消息没有由发送者进行包装,而只是通过 gss_get_mic() 使用 MIC 进行了标记。图 4–9 中说明的过程如下所示:

  1. 启动器使用 gss_get_mic() 对消息进行标记。

  2. 启动器将该消息和 MIC 发送到接受器。

  3. 接受器使用 gss_verify_mic() 检验该消息。

  4. 接受器将该 MIC 发回到启动器。

  5. 启动器使用 gss_verify_mic() 来针对原始消息检验所收到的 MIC。

图 4–9 确认 MIC 数据

该图说明如何确认消息完整性代码。

对于已包装的数据,gss_unwrap() 函数从不生成单独的 MIC,因此,接收者必须根据所收到的未包装的消息生成它。图 4–10 中说明的过程如下所示:

  1. 启动器使用 gss_wrap() 包装消息。

  2. 启动器发送已包装的消息。

  3. 接受器使用 gss_unwrap() 展开该消息。

  4. 接受器调用 gss_get_mic() 以生成未包装的消息的 MIC。

  5. 接受器将派生的 MIC 发送到启动器。

  6. 启动器使用 gss_verify_mic() 将所收到的 MIC 与原始消息进行比较。

对于已经为 GSS-API 数据分配的任何数据空间,应用程序应当解除对其进行分配。相关函数包括 gss_release_buffer(3GSS)gss_release_cred(3GSS)gss_release_name(3GSS)gss_release_oid_set(3GSS)

图 4–10 确认已包装的数据

该图说明如何确认已包装并且具有消息完整性代码的消息。