JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris 开发者安全性指南     Oracle Solaris 10 8/11 Information Library (简体中文)
search filter icon
search icon

文档信息

前言

1.  面向开发者的 Oracle Solaris 安全(概述)

2.  开发特权应用程序

3.  编写 PAM 应用程序和服务

4.  编写使用 GSS-API 的应用程序

5.  GSS-API 客户机示例

GSSAPI 客户机示例概述

GSSAPI 客户机示例结构

运行 GSSAPI 客户机示例

GSSAPI 客户机示例:main() 函数

打开与服务器的连接

建立与服务器的安全上下文

将服务名称转换为 GSS-API 格式

为 GSS-API 建立安全上下文

客户端上的各种 GSSAPI 上下文操作

包装和发送消息

读取和验证 GSS-API 客户机中的签名块

删除安全上下文

6.  GSS-API 服务器示例

7.  编写使用 SASL 的应用程序

8.  Oracle Solaris 加密框架介绍

9.  编写用户级加密应用程序和提供者

10.  使用智能卡框架

A.  基于 C 的 GSS-API 样例程序

B.  GSS-API 参考

C.  指定 OID

D.  SASL 示例的源代码

E.  SASL 参考表

F.  打包和签署加密提供者

词汇表

索引

建立与服务器的安全上下文

建立连接之后,call_server() 会使用 client_establish_context() 函数来创建安全上下文,如下所示:

if (client_establish_context(s, service-name, deleg-flag, oid, &context,
                                  &ret-flags) < 0) {
          (void) close(s);
          return -1;
     }

client_establish_context() 执行以下任务:

将服务名称转换为 GSS-API 格式

client_establish_context() 执行的首个任务是使用 gss_import_name() 将服务名称字符串转换为 GSS-API 内部格式。

示例 5-3 client_establish_context()-转换服务名称

     /*
     * Import the name into target_name.  Use send_tok to save
     * local variable space.
     */

     send_tok.value = service_name;
     send_tok.length = strlen(service_name) + 1;
     maj_stat = gss_import_name(&min_stat, &send_tok,
                        (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &target_name);
     if (maj_stat != GSS_S_COMPLETE) {
          display_status("parsing name", maj_stat, min_stat);
          return -1;
     }

gss_import_name() 提取存储在不透明 GSS_API 缓冲区 send_tok 中的服务名称,然后将服务名称字符串转换为 GSS_API 内部名称 target_namesend_tok 用于节省空间,而不是用于声明新的 gss_buffer_desc。第三个参数类型为 gss_OID,用于指明 send_tok 名称的格式。此示例使用 GSS_C_NT_HOSTBASED_SERVICE,这表示服务采用 service@host 格式。有关此参数的其他可能值,请参见名称类型

为 GSS-API 建立安全上下文

将服务转换为 GSS-API 内部格式之后即可建立上下文。为了尽可能提高可移植性,应当始终循环建立上下文。

进入循环之前,client_establish_context() 会初始化上下文和 token_ptr 参数。使用 token_ptr 时需要进行选择。token_ptr 可以指向 send_tok(发送到服务器的令牌)或 recv_tok(服务器发回的令牌)。

在循环内部,需要检查两项:

以下伪代码对该循环进行了说明:

do gss_init_sec_context() if no context was created exit with error; if the status is neither "complete" nor "in process" release the service namespace and exit with error; if there is a token to send to the server, that is, the size is nonzero send the token; if sending the token fails, release the token and service namespaces. Exit with error; release the namespace for the token that was just sent; if the context is not completely set up receive a token from the server; while the context is not complete

该循环从调用 gss_init_sec_context() 开始,该函数使用以下参数:


注 - 客户机在启动上下文之前无需获取凭证。在客户端,凭证管理通过 GSS-API 以透明方式处理。即,GSS-API 知道如何获取此机制为该主体创建的凭证。因此,应用程序可以向 gss_init_sec_context() 传递缺省凭证。但是在服务器端,服务器应用程序在接受上下文之前必须明确获取服务的凭证。请参见获取凭证


检查了上下文或其一部分是否存在,以及 gss_init_sec_context() 是否返回有效状态之后,connect_to_server() 会检查 gss_init_sec_context() 是否提供了要发送到服务器的令牌。如果不存在任何令牌,表明服务器已经指示不需要其他任何令牌。如果提供了令牌,必须将该令牌发送到服务器。如果发送该令牌失败,则无法确定该令牌和服务的名称空间,并且 connect_to_server() 将退出。以下算法通过查看令牌的长度来检查令牌是否存在:

if (send_tok_length != 0) {
     if (send_token(s, &send_tok) < 0) {
          (void) gss_release_buffer(&min_stat, &send_tok);
          (void) gss_release_name(&min_stat, &target_name);
          return -1;
     }
}

send_token() 不是 GSS-API 函数,需要由用户进行编写。send_token() 函数可将令牌写入到文件描述符中。send_token() 在成功时返回 0,在失败时返回 –1。GSS-API 本身不收发令牌。调用应用程序负责收发 GSS-API 已创建的任何令牌。

下面提供了用于建立上下文循环的源代码。


注 - 此示例的源代码也可以通过 Oracle 下载中心获取。请参见 https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_SMI-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=Security_code-Dev1.1-G-F@CDS-CDS_SMI


示例 5-4 用于建立上下文的循环

/*
 * Perform the context establishment loop.
 *
 * On each pass through the loop, token_ptr points to the token
 * to send to the server (or GSS_C_NO_BUFFER on the first pass).
 * Every generated token is stored in send_tok which is then
 * transmitted to the server; every received token is stored in
 * recv_tok, which token_ptr is then set to, to be processed by
 * the next call to gss_init_sec_context.
 *
 * GSS-API guarantees that send_tok's length will be non-zero
 * if and only if the server is expecting another token from us,
 * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
 * and only if the server has another token to send us.
 */

token_ptr = GSS_C_NO_BUFFER;
*gss_context = GSS_C_NO_CONTEXT;
1234567890123456789012345678901234567890123456789012345678901234567890123456

do {
    maj_stat =
        gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, 
        gss_context, target_name, oid, 
        GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | deleg_flag,
        0, NULL,                      /* no channel bindings */
        token_ptr, NULL,              /* ignore mech type */
        &send_tok, ret_flags, NULL);  /* ignore time_rec */
    if (gss_context == NULL){
        printf("Cannot create context\n");
        return GSS_S_NO_CONTEXT;
    }
    if (token_ptr != GSS_C_NO_BUFFER)
        (void) gss_release_buffer(&min_stat, &recv_tok);
    if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
        display_status("initializing context", maj_stat, min_stat);
        (void) gss_release_name(&min_stat, &target_name);
        return -1;
    }

    if (send_tok.length != 0){
        fprintf(stdout, "Sending init_sec_context token (size=%ld)...",
            send_tok.length);
        if (send_token(s, &send_tok) < 0) {
            (void) gss_release_buffer(&min_stat, &send_tok);
            (void) gss_release_name(&min_stat, &target_name);
            return -1;
        }
    }
    (void) gss_release_buffer(&min_stat, &send_tok);

    if (maj_stat == GSS_S_CONTINUE_NEEDED) {
        fprintf(stdout, "continue needed...");
        if (recv_token(s, &recv_tok) < 0) {
            (void) gss_release_name(&min_stat, &target_name);
            return -1;
        }
        token_ptr = &recv_tok;
    }
    printf("\n");
} while (maj_stat == GSS_S_CONTINUE_NEEDED);

有关 send_token()recv_token() 工作方式的更多信息,请参见各种 GSS-API 样例函数