在两个对等应用程序之间建立上下文之后,即可在发送消息之前对其进行保护。
建立上下文时使用的只是最基本的 GSS-API 保护:验证。根据基础安全机制,GSS-API 提供了另外两个保护级别:
完整性-消息的消息完整性代码 (Message Integrity Code, MIC) 由 gss_get_mic() 函数生成。接受者通过检查 MIC 来确保所收到的消息与所发送的消息完全相同。
gss_get_mic() 和 gss_wrap() 之间的区别如下图所示。使用 gss_get_mic(),接收者可获取用于指示消息是否保持不变的标记;使用 gss_wrap(),接收者除了获取标记外还可获取经过加密的消息。
图 4-7 gss_get_mic() 与 gss_wrap()
要使用哪个函数取决于具体情况。由于 gss_wrap() 包括完整性服务,因此许多程序都使用 gss_wrap()。程序可以测试保密性服务的可用性。随后程序可以根据保密性服务的可用情况,以应用或不应用保密性的方式调用 gss_wrap()。Wrapping and Sending a Message即是一个示例。但是,由于无需展开使用 gss_get_mic() 的消息,因此所使用的 CPU 周期比 gss_wrap() 所使用的要少。所以,不需要保密性的程序可能会使用 gss_get_mic() 来保护消息。
程序可以使用 gss_get_mic() 向消息添加加密 MIC。接受者可以通过调用 gss_verify_mic() 检查消息的 MIC。
与 gss_wrap() 相比,gss_get_mic() 会针对消息和 MIC 生成单独的输出。这意味着发送者应用程序必须既能发送消息又能发送随附的 MIC。更重要的是,接受者必须能够区分消息和 MIC。
以下方法可确保对消息和 MIC 进行正确的处理:
通过程序控制(即状态)。接受者应用程序可能知道对接收函数调用了两次,第一次用于获取消息,第二次用于获取消息的 MIC。
通过标志。发送者和接收者可以标记所包含令牌的类型。
通过用户定义的同时包含消息和 MIC 的令牌结构。
如果 gss_get_mic() 成功完成,则返回 GSS_S_COMPLETE。如果指定的 QOP 无效,则返回 GSS_S_BAD_QOP。有关更多信息,请参见 gss_get_mic(3GSS)。
可以使用 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() 的示例,请参见Wrapping and Sending a Message。
使用 gss_wrap() 来包装消息会增加要发送的数据量。由于所保护的消息包需要适应指定的传输协议,因此 GSS-API 提供了 gss_wrap_size_limit() 函数。gss_wrap_size_limit() 用于计算可以包装的消息的最大大小,使其不至于因变得过大而不适用于该协议。应用程序可以在调用 gss_wrap() 之前截断超出该大小的消息。在实际包装消息之前,请始终检查包装大小限制。
缺省的 QOP 会因不同的 GSS-API 实现而异。因此,即使指定了缺省的 QOP,所包装消息的大小也会有所不同。下图说明了这种可能性:
无论是否应用了保密性,gss_wrap() 仍然会增加消息的大小。gss_wrap() 可将 MIC 嵌入到所传送的消息中。但是,对消息进行加密会进一步增加消息的大小。此过程如下图所示。
如果 gss_wrap_size_limit() 成功完,则返回 GSS_S_COMPLETE。如果指定的 QOP 无效,则返回 GSS_S_BAD_QOP。Wrapping and Sending a Message中提供了一个说明如何使用 gss_wrap_size_limit() 返回原始消息最大大小的示例。
成功完成此调用并不一定保证 gss_wrap() 可以保护长度为 max-input-size 个字节的消息。能否保护消息取决于调用 gss_wrap() 时系统资源是否可用。有关更多信息,请参见 gss_wrap_size_limit(3GSS) 手册页。
由于上下文启动器会向接受器传送顺序的数据包,因此某些机制允许上下文接受器检查顺序是否正确。这些检查包括数据包是否按正确的顺序到达以及是否存在不需要的数据包重复。请参见下图。接受器可以在检验数据包和展开数据包的过程中检查这两种情况。有关更多信息,请参见Unwrapping the Message。
图 4-8 消息重放和消息失序
启动器可以使用 gss_init_sec_context() 来检查顺序,方法是通过 GSS_C_REPLAY_FLAG 或 GSS_C_SEQUENCE_FLAG 对 req_flags 参数应用逻辑 OR。
接受者展开或检验所传送的消息之后,会向发送者返回确认信息。这意味着会发回该消息的 MIC。请考虑以下情况:消息没有由发送者进行包装,而只是通过 gss_get_mic() 使用 MIC 进行了标记。
Figure 4–9 中说明的过程如下所示:
启动器使用 gss_get_mic() 对消息进行标记。
启动器将该消息和 MIC 发送到接受器。
接受器使用 gss_verify_mic() 检验该消息。
接受器将该 MIC 发回到启动器。
启动器使用 gss_verify_mic() 针对原始消息检验所收到的 MIC。
图 4-9 确认 MIC 数据
对于已包装的数据,gss_unwrap() 函数从不生成单独的 MIC,因此,接受者必须根据所收到的未包装的消息生成它。
Figure 4–10 中说明的过程如下所示:
启动器使用 gss_wrap() 包装消息。
启动器发送已包装的消息。
接受器使用 gss_unwrap() 展开该消息。
接受器调用 gss_get_mic() 以生成未包装的消息的 MIC。
接受器将派生的 MIC 发送到启动器。
启动器使用 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 确认已包装的数据