JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris 11 开发者安全性指南     Oracle Solaris 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.  Oracle Solaris 密钥管理框架介绍

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

B.  GSS-API 参考

C.  指定 OID

D.  SASL 示例的源代码

E.  SASL 参考表

词汇表

索引

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

建立连接之后,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 下载中心获取。 请参见 http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html


示例 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 样例函数