⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rfc1050.txt

📁 RFC中文技术文档
💻 TXT
📖 第 1 页 / 共 3 页
字号:
 
       /*
        * RPC请求的响应实体;
        * 调用消息要么被接受要么被拒绝
        */
       union reply_body switch (reply_stat stat) {
       case MSG_ACCEPTED:
          accepted_reply areply;
       case MSG_DENIED:
          rejected_reply rreply;
       } reply;
 
/*
               *   当服务器接受RPC请求时的响应:
        *即使请求被接受,也可能会有错误。
        * 第一个字段是服务器产生的认证校验符,为了使调用者能够识别服务器。
        *接下来是一个判别式是枚举类型accept_stat的联合。
*联合中SUCCESS的一个分支是特定的协议。
        *联合中The PROG_UNAVAIL, PROC_UNAVAIL和GARBAGE_ARGS
*的分支为空。PROG_MISMATCH分支确定了服务器支持的远程
*程序的最低和最高版本号。
        */
       struct accepted_reply {
          opaque_auth verf;
          union switch (accept_stat stat) {
          case SUCCESS:
             opaque results[0];
             /*
              *具体的过程结果从这里开始
              */
           case PROG_MISMATCH:
              struct {
                 unsigned int low;
                 unsigned int high;
              } mismatch_info;
           default:
              /*
*空。这些情况包括PROG_UNAVAIL,
* PROC_UNAVAIL和GARBAGE_ARGS.
               */
              void;
           } reply_data;
       };
 
       /*
        *当服务器拒绝RPC请求时的响应:
        *请求可能由于两种原因被拒绝:一种是服务器没有运行RPC协议的
*兼容版本(RPC_MISMATCH),另一种是服务器不认证调用者(AUTH_ERROR)。
*在RPC版本不匹配的情况下,服务器返回所支持的最低和最高版本号。
*在不认证的情况下,返回失败状态。
        */
       union rejected_reply switch (reject_stat stat) {
       case RPC_MISMATCH:
          struct {
             unsigned int low;
unsigned int high;
        } mismatch_info;
       case AUTH_ERROR:
          auth_stat stat;
       };
 
9.认证协议
   象前面所说的那样,认证参数是不透明的,但是对于RPC协议的其余部分是可调整的。这一节说明了在Sun中实现(或是由Sun支持的)的认证的“特征值”。在其它的场所中可以自由得创造新的认证类型。特征值的分配的规则和程序号的分配规则是一样的。
9.1 不认证 
   通常过程会在调用者不知道它是谁或者服务器不关心调用者是谁的情况下调用。在这种情况下RPC消息中的证书,校验符和响应校验符的“特征值”(opaque_auth的联合的判别式)为"AUTH_NULL"。opaque_auth的实体中的字节没有定义。建议这些opaque长度为0。
9.2 UNIX 认证 
   远程过程的调用者可能希望象在UNIX系统中那样标识它自己。RPC调用消息中的证书判别式的值是"AUTH_UNIX"。这些证书的opaque实体编码成下面这样的结构:

         struct auth_unix {
            unsigned int stamp;
            string machinename<255>;
            unsigned int uid;
            unsigned int gid;
            unsigned int gids<10>;
         };
 
   "stamp"是一个调用者机器产生的二进制标识符(ID)。"machinename"是调用者机器的名字(例如 “krypton”)。 "uid"是调用者的有效用户标识符ID。 "gid"是调用者的有效组标识符ID。 "gids"是一个包含调用者作为成员的组的计数数组。伴随着证书的校验符应该是"AUTH_NULL"(上面定义的)

   从服务器收到的响应消息中的响应校验符的判别式的值可能是"AUTH_NULL" ,或者 是"AUTH_SHORT"。在"AUTH_SHORT"的情况下,响应校验符的字符串字节编码成不透明的结构。这个新的不透明结构现在可以传递给服务器以代替原来的"AUTH_UNIX"特征值证书。服务器保留一个缓冲区用来把这个速记下来的不透明结构(通过一个"AUTH_SHORT"类型响应校验符传回)映射到调用者原来的证书上。调用者可以使用新的证书节省网络带宽和服务器上的cpu周期。

   服务器可能在任一时间刷新这个速记下来的不透明结构。如果这种情况发生,远程过程调用消息将由于认证错误被拒绝。失败的原因将是"AUTH_REJECTEDCRED"。在这时,调用者可能希望试试原来的"AUTH_UNIX"证书类型。
9.3 DES认证
    UNIX认证遇到了下面两个主要问题:
 
         (1) 命名太面向于UNIX
         (2) 没有校验符,所以证书很容易伪造
 
    DES认证努力来解决这两个问题。
 
9.3.1 命名
 
   处理第一个问题的方法是通过使用一个简单的字符串代替操作系统特定的整数来定位调用者。这个字符串就作为 "netname"或者调用者的网络名。除了在鉴别调用者之外,不允许服务器在任何其它的方面解释调用者名字中的内容。因此,网络名对于在Internet中的每一个调用者来说都应该是唯一的。

   由每一个操作系统上的DES认证实现来为它的用户产生网络名,以确保当用户造访远程服务器的时候,他的网络名是唯一的。操作系统也知道怎样区分本地系统中的用户。把这种机制扩展到网络上通常存在着一些小问题。例如,在Sun上的具有用户ID号为515的UNIX用户可能被分配给下面的网络名: “unix.515@sun.com"。这个网络名包含三项以使服务器确认它是唯一的。在Internet网上叫做“sun.com”的命名域只有一个。在这个域中用户ID是515的UNIX用户也仅有一个。但是,在其它的操作系统上可能有另一个用户,例如在VMS上,也在同样的命名域中,碰巧也有同样的用户ID。为了确保两个用户被区分,我们加入操作系统名。所以一个用户是"unix.515@sun.com",另一个是“vms.515@sun.com”。

   第一个字段实际上是一种命名方法,而不是一个操作系统名。现在仅仅是碰巧在命名方法和操作系统之间存在一对一对应。如果全世界在命名标准上取得一致,第一个字段应该是标准的名字,而不是一个操作系统名。

9.3.2 DES认证校验
   不像UNIX认证,DES认证有一个校验符,这可以使服务器验证客户的证书(反之客户也可以验证服务器的证书)。校验符的内容主要是一个加密的时间戳。服务器可以解密这个时间戳。如果它接近真实的时间,那么客户一定已经正确的加密了它。客户端能加密它的唯一方法是知道这个RPC会话的“会话密钥”。如果客户端知道这个会话密钥,那么它就是真正的客户端。
 
   会话密钥是由一个由客户端产生的DES密钥[5],在第一次RPC调用时通知服务器。会话密钥在第一次事务中由一个公钥模式加密。使用在DES认证中的特别的公钥模式是Diffie-Hellman [3],它具有128比特位的密钥长度。这种加密方法的细节以后讨论。

    为了完成工作,客户端和服务器需要相同的时间概念。如果网络时间同步不能保证,那么客户端可以在开始会话前与服务器建立同步。也许要与Internet时间服务器协商(TIME [4])。

    服务器判断一个客户端时间戳是否有效的方法有点复杂。对于除了第一次事务之外的其它事务,服务器只检查两件事。

(1) 这个时间戳比来自同一个客户端的前一个时间戳大

  (2) 这个时间戳没有过期。
 
   如果服务器时间比客户端的时间戳与客户端的窗口值(window)相加后的总和还要晚,这个时间戳过期。 “window”是客户端在它的第一次事务中传递(已加密过)给服务器的一个数字。你可以把它看作是证书的生存期。

    以上说明了除第一次事务的每一次事务。在第一次事务中,服务器仅检查时间戳没有过期。如果就是所作的全部工作的话,对于客户端来说,发送随机的数据代替时间戳将会非常容易,这会有很大的成功机会。作为一个附加的检查,客户端在第一次事务中发送一个叫“窗口校验符”的加密项,它必须等于窗口值减1,否则服务器将拒绝这个证书。

    客户端也必须检查从服务器返回的校验符,以确定服务器是合法的。服务器把它从客户端收到的加密时间戳减一秒后再送回给客户端。如果客户端得到数据与此不同,它将拒绝。
 
9.3.3 昵称和时钟同步
    
在第一次事务之后,服务器DES认证子系统在它返回给客户端的校验符中有一个 “昵称” 整数,客户端可以在以后的每次事务中使用这个昵称来代替它的网络名,加密的DES密钥和窗口。昵称更像一个在服务器上表的索引,在这张表中存储着每一个客户端的网络名,DES密钥译文和窗口。

    尽管客户端和服务器的时钟在开始时被同步,但是他们可能再次变得不同步。当这种情况发生后,客户端RPC子系统可能在应该需要再次同步的时候得到"RPC_AUTHERROR"。

    客户端即使在与服务器同步的情况下仍然可能得到"RPC_AUTHERROR"错误。这个原因就是服务器的昵称表大小有限,它可以在它需要的时候随时刷新表中的条目。在这种情况下,客户端应该重新发送它的原来的证书,服务器将给它一个新的昵称。如果服务器崩溃,昵称表中的条目得到刷新,所有的客户端都将必须重新发送它的原来的证书。

9.3.4  DES认证协议规范(用XDR语言描述)
     /*
*有两种证书:一种是客户端使用它的全称网络名,另一种是客户端使用
*由服务器发给它的昵称(仅仅是一个无符号整数)。在第一次与服务器的事务中,
*客户端必须使用它的全称名。服务器将返回给客户端它的昵称。
*客户端可以在以后的与服务器的事务中使用它的昵称。并不是一定要使用昵称,
*但是使用昵称将是一个明智的选择。
     */
enum authdes_namekind {
       ADN_FULLNAME = 0,
       ADN_NICKNAME = 1
    };
 
    /*
     *一个由DES加密的64比特数据块。
     */
    typedef opaque des_block[8];
 
    /*
     * 网络用户名的最大长度
     */
    const MAXNETNAMELEN = 255;
 
    /*
* 全称包括客户端的网络名,一个加密的会话密钥和窗口。窗口实际上就是
* 证书的生存期。如果在校验符中的时间戳指示的时间加上窗口后过期,
*那么服务器应该使请求过期,而且不承认它。为了确保请求不会重放,
*服务器应该保持时间戳比前一个看到的时间戳大,除非这是第一个事务。
*在第一个事务中,服务器只检查窗口校验符是一个小于窗口的值。
     */
    struct authdes_fullname {
       string name<MAXNETNAMELEN>;  /* 客户端名字 */
       des_block key;               /* 公用密钥加密过的会话密钥*/
       unsigned int window;         /*  加密过的窗口  */
    };
 
    /*
     *一个证书要么是全称要么是昵称
     */
    union authdes_cred switch (authdes_namekind adc_namekind) {
    case ADN_FULLNAME:
       authdes_fullname adc_fullname;
    case ADN_NICKNAME:
       unsigned int adc_nickname;
    };
 
    /*
     *时间戳从1970年1月1日午夜开始给时间编码
     */
    struct timestamp {
         unsigned int seconds;    /* 秒 */
         unsigned int useconds;   /* 微秒 */
};
 
    /*
     * 校验符:客户端的种类
     * 窗口的校验符仅使用在第一次事务中,在与全称证书的关联中,
*这些项目在加密前打包在下面的结构中。
     *
     * struct {
     *     adv_timestamp;        --  one DES block
     *     adc_fullname.window;  --   one half DES block
     *     adv_winverf;          --   one half DES block
     * }
     *这个结构以一个输入的0向量使用CBC加密模式加密
     * 所有的其它时间戳加密是使用ECB加密模式加密
     */
    struct authdes_verf_clnt {
       timestamp adv_timestamp;    /* 加密的时间戳     */
       unsigned int adv_winverf;   /* 加密的窗口校验符  */
    };
 
    /*
     * 校验符:服务器种类
* 服务器把这个加密的时间戳减一秒后,返回给客户端。
* 服务器也告诉客户端它的昵称(未加密),已备在将来的事务中使用。
     */
    struct authdes_verf_svr {
       timestamp adv_timeverf;     /* 加密的校验符  */
       unsigned int adv_nickname;  /* 客户端新的昵称*/
    };
 
9.3.5  Diffie-Hellman 加密方法
 
    在这种模式中,有两个常数"PROOT" 和"MODULUS"。Sun为DES认证协议选择了特定的值:
        const PROOT = 2;
        const MODULUS = "b520985fb31fcaf75036701e37d8b857"; /* 十六进制 */
 
   这种模式工作的过程最好用一个例子来说明。假设有两个人“A”和“B”想互相发送加密的消息。所以,A和B都随机产生一个“秘密”密钥,这个密钥他们并不想让其它人知道。把这两个密钥表示为SK(A) 和 SK(B)。他们也在一个公开的姓名地址录中发布他们的“公用”密钥。公用密钥由以下方式计算出。

            PK(A) = ( PROOT ** SK(A) ) mod MODULUS
            PK(B) = ( PROOT ** SK(B) ) mod MODULUS
 
   "**"符号在这里表示求幂。现在A和B都能得到在他们之间的“公共”密钥,而不需要暴露他们的秘密密钥。公共密钥在这里描述为CK(A, B), 

         A电脑:
 
            CK(A, B) = ( PK(B) ** SK(A)) mod MODULUS
 
          B电脑:
 
            CK(A, B) = ( PK(A) ** SK(B)) mod MODULUS
 
         这两个值是相等的:
 
            (PK(B) ** SK(A)) mod MODULUS = (PK(A) ** SK(B)) mod MODULUS
 
         我们去掉"mod MODULUS"的取模算法部分来进行简化。

            PK(B) ** SK(A) = PK(A) ** SK(B)
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -