• 13 <- index

  • A. プロトコル処理のための擬似コード English

    この付録においては、クライアントとサーバーでメッセージがどのように作成され、解釈されるかを示す擬似コードについて説明します。

    A.1.  KRB_AS_REQ 生成 (English)

            request.pvno := protocol version; /* pvno = 5 */
            request.msg-type := message type; /* type = KRB_AS_REQ */
            if(pa_enc_timestamp_required) then
                    request.padata.padata-type = PA-ENC-TIMESTAMP;
                    get system_time;
                    padata-body.patimestamp,pausec = system_time;
                    encrypt padata-body into request.padata.padata-value
                            using client.key; /* パスワードから取り出した */
            endif
    
            body.kdc-options := users's preferences;
            body.cname := user's name;
            body.realm := user's realm;
            body.sname := service's name; /* 通常 "krbtgt",
                                             "localrealm" */
    
            if (body.kdc-options.POSTDATED is set) then
                    body.from := requested starting time;
            else
                    omit body.from;
            endif
    
            body.till := requested end time;
    
            if (body.kdc-options.RENEWABLE is set) then
                    body.rtime := requested final renewal time;
            endif
    
            body.nonce := random_nonce();
            body.etype := requested etypes;
    
            if (user supplied addresses) then
                    body.addresses := user's addresses;
            else
                    omit body.addresses;
            endif
    
            omit body.enc-authorization-data;
            request.req-body := body;
            kerberos := lookup(name of local kerberos server (or servers));
            send(packet,kerberos);
            wait(for response);
    
            if (timed_out) then
                    retry or use alternate server;
            endif
    

    A.2.  KRB_AS_REQ 検証および KRB_AS_REP 生成 (English)

            decode message into req;
            client := lookup(req.cname,req.realm);
            server := lookup(req.sname,req.realm);
            get system_time;
            kdc_time := system_time.seconds;
    
            if (!client) then
                    /* データベース内にクライアントがない */
                    error_out(KDC_ERR_C_PRINCIPAL_UNKNOWN);
            endif
    
            if (!server) then
                    /* データベース内にサーバーがない */
                    error_out(KDC_ERR_S_PRINCIPAL_UNKNOWN);
            endif
            if(client.pa_enc_timestamp_required and
               pa_enc_timestamp not present) then
                    error_out(KDC_ERR_PREAUTH_REQUIRED(PA_ENC_TIMESTAMP));
            endif
    
            if(pa_enc_timestamp present) then
                    decrypt req.padata-value into decrypted_enc_timestamp
                            using client.key;
                            using auth_hdr.authenticator.subkey;
                    if (decrypt_error()) then
                            error_out(KRB_AP_ERR_BAD_INTEGRITY);
                    if(decrypted_enc_timestamp is not within allowable
                            skew) then error_out(KDC_ERR_PREAUTH_FAILED);
                    endif
                    if(decrypted_enc_timestamp and usec is replay)
                            error_out(KDC_ERR_PREAUTH_FAILED);
                    endif
                    add decrypted_enc_timestamp and usec to replay cache;
            endif
    
            use_etype := first supported etype in req.etypes;
    
            if (no support for req.etypes) then
                    error_out(KDC_ERR_ETYPE_NOSUPP);
            endif
    
            new_tkt.vno := ticket version; /* = 5 */
            new_tkt.sname := req.sname;
            new_tkt.srealm := req.srealm;
            reset all flags in new_tkt.flags;
    
            /* ローカル ポリシーはこれらのフラグの処理に影響を与える */
            /* ことがあります。たとえば、レルムによっては、更新可能  */
            /* なチケットを拒否します。                            */
    
            if (req.kdc-options.FORWARDABLE is set) then
                    set new_tkt.flags.FORWARDABLE;
            endif
    
            if (req.kdc-options.PROXIABLE is set) then
                    set new_tkt.flags.PROXIABLE;
            endif
    
            if (req.kdc-options.ALLOW-POSTDATE is set) then
                    set new_tkt.flags.ALLOW-POSTDATE;
            endif
    
            if ((req.kdc-options.RENEW is set) or
                (req.kdc-options.VALIDATE is set) or
                (req.kdc-options.PROXY is set) or
                (req.kdc-options.FORWARDED is set) or
                (req.kdc-options.ENC-TKT-IN-SKEY is set)) then
                    error_out(KDC_ERR_BADOPTION);
            endif
            new_tkt.session := random_session_key();
            new_tkt.cname := req.cname;
            new_tkt.crealm := req.crealm;
            new_tkt.transited := empty_transited_field();
            new_tkt.authtime := kdc_time;
            if (req.kdc-options.POSTDATED is set) then
               if (against_postdate_policy(req.from)) then
                    error_out(KDC_ERR_POLICY);
               endif
               set new_tkt.flags.INVALID;
               new_tkt.starttime := req.from;
            else
               omit new_tkt.starttime; /* 省略したときには authtime として
                                          扱われる */
            endif
            if (req.till = 0) then
                    till := infinity;
            else
                    till := req.till;
            endif
            new_tkt.endtime := min(till,
                                  new_tkt.starttime+client.max_life,
                                  new_tkt.starttime+server.max_life,
                                  new_tkt.starttime+max_life_for_realm);
            if ((req.kdc-options.RENEWABLE-OK is set) and
                (new_tkt.endtime < req.till)) then
                    /* ここでは、後の処理のために 
                    RENEWABLE オプションをセットする */
                    req.rtime := req.till;
            endif
            if (req.rtime = 0) then
                    rtime := infinity;
            else
                    rtime := req.rtime;
            endif
            if (req.kdc-options.RENEWABLE is set) then
                    set new_tkt.flags.RENEWABLE;
                    new_tkt.renew-till := min(rtime,
                    new_tkt.starttime+client.max_rlife,
                    new_tkt.starttime+server.max_rlife,
                    new_tkt.starttime+max_rlife_for_realm);
            else
                    omit new_tkt.renew-till; /* RENEWABLE の場合だけ表示される*/
            endif
            if (req.addresses) then
                    new_tkt.caddr := req.addresses;
            else
                    omit new_tkt.caddr;
            endif
            new_tkt.authorization_data := empty_authorization_data();
            encode to-be-encrypted part of ticket into OCTET STRING;
            new_tkt.enc-part := encrypt OCTET STRING
                using etype_for_key(server.key), server.key, server.p_kvno;
            /* 応答処理開始 */
            resp.pvno := 5;
            resp.msg-type := KRB_AS_REP;
            resp.cname := req.cname;
            resp.crealm := req.realm;
            resp.ticket := new_tkt;
            resp.key := new_tkt.session;
            resp.last-req := fetch_last_request_info(client);
            resp.nonce := req.nonce;
            resp.key-expiration := client.expiration;
            resp.flags := new_tkt.flags;
            resp.authtime := new_tkt.authtime;
            resp.starttime := new_tkt.starttime;
            resp.endtime := new_tkt.endtime;
            if (new_tkt.flags.RENEWABLE) then
                    resp.renew-till := new_tkt.renew-till;
            endif
            resp.realm := new_tkt.realm;
            resp.sname := new_tkt.sname;
            resp.caddr := new_tkt.caddr;
            encode body of reply into OCTET STRING;
            resp.enc-part := encrypt OCTET STRING
                             using use_etype, client.key, client.p_kvno;
            send(resp);
    

    A.3.  KRB_AS_REP 検証 (English)

            decode response into resp;
            if (resp.msg-type = KRB_ERROR) then
                    if(error = KDC_ERR_PREAUTH_REQUIRED(PA_ENC_TIMESTAMP))
                            then set pa_enc_timestamp_required;
                            goto KRB_AS_REQ;
                    endif
                    process_error(resp);
                    return;
            endif
    
            /* エラーが発生した場合は、応答を破棄し、 */
            /* 応答のセッション鍵を即座に 0 にする    */
    
            key = get_decryption_key(resp.enc-part.kvno, resp.enc-part.etype,
                                     resp.padata);
            unencrypted part of resp := decode of decrypt of resp.enc-part
                                    using resp.enc-part.etype and key;
            zero(key);
            if (common_as_rep_tgs_rep_checks fail) then
                    destroy resp.key;
                    return error;
            endif
            if near(resp.princ_exp) then
                    print(warning message);
            endif
            save_for_later(ticket,session,client,server,times,flags);
    

    A.4.  KRB_AS_REP および KRB_TGS_REP の一般チェック (English)

            if (decryption_error() or
                (req.cname != resp.cname) or
                (req.realm != resp.crealm) or
                (req.sname != resp.sname) or
                (req.realm != resp.realm) or
                (req.nonce != resp.nonce) or
                (req.addresses != resp.caddr)) then
                    destroy resp.key;
                    return KRB_AP_ERR_MODIFIED;
            endif
            /* 適切なフラグだけがセットされていることを確認のこと  */
            if (!check_flags_for_compatability(req.kdc-options,resp.flags))
                    then destroy resp.key;
                    return KRB_AP_ERR_MODIFIED;
            endif
            if ((req.from = 0) and
                (resp.starttime is not within allowable skew)) then
                    destroy resp.key;
                    return KRB_AP_ERR_SKEW;
            endif
            if ((req.from != 0) and (req.from != resp.starttime)) then
                    destroy resp.key;
                    return KRB_AP_ERR_MODIFIED;
            endif
            if ((req.till != 0) and (resp.endtime > req.till)) then
                    destroy resp.key;
                    return KRB_AP_ERR_MODIFIED;
            endif
            if ((req.kdc-options.RENEWABLE is set) and
                (req.rtime != 0) and (resp.renew-till > req.rtime)) then
                    destroy resp.key;
                    return KRB_AP_ERR_MODIFIED;
            endif
            if ((req.kdc-options.RENEWABLE-OK is set) and
                (resp.flags.RENEWABLE) and
                (req.till != 0) and
                (resp.renew-till > req.till)) then
                    destroy resp.key;
                    return KRB_AP_ERR_MODIFIED;
            endif
    

    A.5.  KRB_TGS_REQ 生成 (English)

            /* make_application_request は、適切なチケット-         */
            /* グランティング チケットを取得するのにこのルーチンを  */
            /* 再帰的に実行する必要があるかもしれません。           */
            request.pvno := protocol version; /* pvno = 5 */
            request.msg-type := message type; /* type = KRB_TGS_REQ */
            body.kdc-options := users's preferences;
            /* TGT がエンドユーザーのレルム用ではない場合、sname  */
            /* はエンド レルムの TGT になり、要求したチケット     */
            /* (body.realm) のレルムは、要求を出している TGS の   */
            /* レルムになります。                                 */
            body.sname := service's name;
            body.realm := service's realm;
            if (body.kdc-options.POSTDATED is set) then
                    body.from := requested starting time;
            else
                    omit body.from;
            endif
            body.till := requested end time;
            if (body.kdc-options.RENEWABLE is set) then
                    body.rtime := requested final renewal time;
            endif
            body.nonce := random_nonce();
            body.etype := requested etypes;
            if (user supplied addresses) then
                    body.addresses := user's addresses;
            else
                    omit body.addresses;
            endif
            body.enc-authorization-data := user-supplied data;
            if (body.kdc-options.ENC-TKT-IN-SKEY) then
                    body.additional-tickets_ticket := second TGT;
            endif
            request.req-body := body;
            check := generate_checksum (req.body,checksumtype);
            request.padata[0].padata-type := PA-TGS-REQ;
            request.padata[0].padata-value := create a KRB_AP_REQ using
                                          the TGT and checksum
            /* 必要/供給に応じて他の padata を追加する */
            kerberos := lookup(name of local kerberose server (or servers));
            send(packet,kerberos);
            wait(for response);
            if (timed_out) then
                    retry or use alternate server;
            endif
    A.6. KRB_TGS_REQ 検証および KRB_TGS_REP 生成  (English)
    /* アプリケーション要求を読み取るには、まずチケットを発行した サーバーを判断し、
        復号するための鍵を選択する必要があります。 
        サーバー名は、チケットのプレーンテキスト部分に表示されます。 */ 
            if (no KRB_AP_REQ in req.padata) then
                    error_out(KDC_ERR_PADATA_TYPE_NOSUPP);
            endif
            verify KRB_AP_REQ in req.padata;
            /* Kerberos サーバーが動作しているレルムは、チケット-
               グランティング チケットのインスタンスによって判断されて
               います。チケット-グランティング チケット内のレルムは、
               チケット-グランティング チケットが発行されたレルムです。
               1 つの Kerberos サーバーは、複数のレルムをサポート
               できます。 */
            auth_hdr := KRB_AP_REQ;
            tgt := auth_hdr.ticket;
            if (tgt.sname is not a TGT for local realm and is not
                    req.sname) then error_out(KRB_AP_ERR_NOT_US);
            realm := realm_tgt_is_for(tgt);
            decode remainder of request;
            if (auth_hdr.authenticator.cksum is missing) then
                    error_out(KRB_AP_ERR_INAPP_CKSUM);
            endif
            if (auth_hdr.authenticator.cksum type is not supported) then
                    error_out(KDC_ERR_SUMTYPE_NOSUPP);
            endif
            if (auth_hdr.authenticator.cksum is not both collision-proof
                and keyed)  then
                    error_out(KRB_AP_ERR_INAPP_CKSUM);
            endif
            set computed_checksum := checksum(req);
            if (computed_checksum != auth_hdr.authenticatory.cksum) then
                    error_out(KRB_AP_ERR_MODIFIED);
            endif
            server := lookup(req.sname,realm);
            if (!server) then
                    if (is_foreign_tgt_name(server)) then
                            server := best_intermediate_tgs(server);
                    else
                            /* データベース内にサーバーがありません */
                            error_out(KDC_ERR_S_PRINCIPAL_UNKNOWN);
                    endif
            endif
            session := generate_random_session_key();
            use_etype := first supported etype in req.etypes;
            if (no support for req.etypes) then
                    error_out(KDC_ERR_ETYPE_NOSUPP);
            endif
            new_tkt.vno := ticket version; /* = 5 */
            new_tkt.sname := req.sname;
            new_tkt.srealm := realm;
            reset all flags in new_tkt.flags;
            /* ローカル ポリシーはこれらのフラグの処理に影響を与える */
            /* ことがあります。たとえば、レルムによっては、更新可能  */
            /* なチケットを拒否します。                              */
            new_tkt.caddr := tgt.caddr;
            resp.caddr := NULL; /* 変更された場合だけこれを入れます。 */
            if (req.kdc-options.FORWARDABLE is set) then
                    if (tgt.flags.FORWARDABLE is reset) then
                            error_out(KDC_ERR_BADOPTION);
                    endif
                    set new_tkt.flags.FORWARDABLE;
            endif
            if (req.kdc-options.FORWARDED is set) then
                    if (tgt.flags.FORWARDABLE is reset) then
                            error_out(KDC_ERR_BADOPTION);
                    endif
                    set new_tkt.flags.FORWARDED;
                    new_tkt.caddr := req.addresses;
                    resp.caddr := req.addresses;
            endif
            if (tgt.flags.FORWARDED is set) then
                    set new_tkt.flags.FORWARDED;
           endif
            if (req.kdc-options.PROXIABLE is set) then
                    if (tgt.flags.PROXIABLE is reset)
                            error_out(KDC_ERR_BADOPTION);
                    endif
                    set new_tkt.flags.PROXIABLE;
            endif
            if (req.kdc-options.PROXY is set) then
                    if (tgt.flags.PROXIABLE is reset) then
                            error_out(KDC_ERR_BADOPTION);
                    endif
                    set new_tkt.flags.PROXY;
                    new_tkt.caddr := req.addresses;
                    resp.caddr := req.addresses;
            endif
            if (req.kdc-options.POSTDATE is set) then
                    if (tgt.flags.POSTDATE is reset)
                            error_out(KDC_ERR_BADOPTION);
                    endif
                    set new_tkt.flags.POSTDATE;
            endif
            if (req.kdc-options.POSTDATED is set) then
                    if (tgt.flags.POSTDATE is reset) then
                            error_out(KDC_ERR_BADOPTION);
                    endif
                    set new_tkt.flags.POSTDATED;
                    set new_tkt.flags.INVALID;
                    if (against_postdate_policy(req.from)) then
                            error_out(KDC_ERR_POLICY);
                    endif
                    new_tkt.starttime := req.from;
            endif
            if (req.kdc-options.VALIDATE is set) then
                    if (tgt.flags.INVALID is reset) then
                            error_out(KDC_ERR_POLICY);
                    endif
                    if (tgt.starttime > kdc_time) then
                            error_out(KRB_AP_ERR_NYV);
                    endif
                    if (check_hot_list(tgt)) then
                            error_out(KRB_AP_ERR_REPEAT);
                    endif
                    tkt := tgt;
                    reset new_tkt.flags.INVALID;
            endif
            if (req.kdc-options.(any flag except ENC-TKT-IN-SKEY, RENEW,
                                 and those already processed) is set) then
                    error_out(KDC_ERR_BADOPTION);
            endif
            new_tkt.authtime := tgt.authtime;
            if (req.kdc-options.RENEW is set) then
              /* endtime がすでに過ぎている場合は、チケットは初回の認証段階で */
              /* 拒否されているので、ここで再度チェックする必要はありません。 */
                    if (tgt.flags.RENEWABLE is reset) then
                            error_out(KDC_ERR_BADOPTION);
                    endif
                    if (tgt.renew-till >= kdc_time) then
                            error_out(KRB_AP_ERR_TKT_EXPIRED);
                    endif
                    tkt := tgt;
                    new_tkt.starttime := kdc_time;
                    old_life := tgt.endttime - tgt.starttime;
                    new_tkt.endtime := min(tgt.renew-till,
                                           new_tkt.starttime + old_life);
            else
                    new_tkt.starttime := kdc_time;
                    if (req.till = 0) then
                            till := infinity;
                    else
                            till := req.till;
                    endif
                    new_tkt.endtime := min(till,
                                       new_tkt.starttime+client.max_life,
                                       new_tkt.starttime+server.max_life,
                                       new_tkt.starttime+max_life_for_realm,
                                       tgt.endtime);
                    if ((req.kdc-options.RENEWABLE-OK is set) and
                        (new_tkt.endtime < req.till) and
                        (tgt.flags.RENEWABLE is set) then
                            /* 後の処理のために RENEWABLE オプションを  */
                            /* セットする                             */
                            set req.kdc-options.RENEWABLE;
                            req.rtime := min(req.till, tgt.renew-till);
                    endif
            endif
            if (req.rtime = 0) then
                    rtime := infinity;
            else
                    rtime := req.rtime;
            endif
            if ((req.kdc-options.RENEWABLE is set) and
                (tgt.flags.RENEWABLE is set)) then
                    set new_tkt.flags.RENEWABLE;
                    new_tkt.renew-till := min(rtime,
                    new_tkt.starttime+client.max_rlife,
                    new_tkt.starttime+server.max_rlife,
                    new_tkt.starttime+max_rlife_for_realm,
                    tgt.renew-till);
            else
                    new_tkt.renew-till := OMIT;
                                  /* renew-till フィールドを省略する */
            endif
            if (req.enc-authorization-data is present) then
                    decrypt req.enc-authorization-data
                            into    decrypted_authorization_data
                            using auth_hdr.authenticator.subkey;
                    if (decrypt_error()) then
                            error_out(KRB_AP_ERR_BAD_INTEGRITY);
                    endif
            endif
            new_tkt.authorization_data :=
            req.auth_hdr.ticket.authorization_data +
                                     decrypted_authorization_data;
            new_tkt.key := session;
            new_tkt.crealm := tgt.crealm;
            new_tkt.cname := req.auth_hdr.ticket.cname;
            if (realm_tgt_is_for(tgt) := tgt.realm) then
                    /* ローカル レルムが発行した tgt */
                    new_tkt.transited := tgt.transited;
            else
                    /* 他のレルムによってこのレルム用に発行されている */
                    if (tgt.transited.tr-type not supported) then
                            error_out(KDC_ERR_TRTYPE_NOSUPP);
                    endif
                    new_tkt.transited
                       := compress_transited(tgt.transited + tgt.realm)
            endif
            encode encrypted part of new_tkt into OCTET STRING;
            if (req.kdc-options.ENC-TKT-IN-SKEY is set) then
                    if (server not specified) then
                            server = req.second_ticket.client;
                    endif
                    if ((req.second_ticket is not a TGT) or
                        (req.second_ticket.client != server)) then
                            error_out(KDC_ERR_POLICY);
                    endif
                    new_tkt.enc-part := encrypt OCTET STRING using
                            using etype_for_key(second-ticket.key),
                                                          second-ticket.key;
            else
                    new_tkt.enc-part := encrypt OCTET STRING
                            using etype_for_key(server.key), server.key,
                                                          server.p_kvno;
            endif
            resp.pvno := 5;
            resp.msg-type := KRB_TGS_REP;
            resp.crealm := tgt.crealm;
            resp.cname := tgt.cname;
            resp.ticket := new_tkt;
            resp.key := session;
            resp.nonce := req.nonce;
            resp.last-req := fetch_last_request_info(client);
            resp.flags := new_tkt.flags;
            resp.authtime := new_tkt.authtime;
            resp.starttime := new_tkt.starttime;
            resp.endtime := new_tkt.endtime;
            omit resp.key-expiration;
            resp.sname := new_tkt.sname;
            resp.realm := new_tkt.realm;
            if (new_tkt.flags.RENEWABLE) then
                    resp.renew-till := new_tkt.renew-till;
            endif
            encode body of reply into OCTET STRING;
            if (req.padata.authenticator.subkey)
                    resp.enc-part := encrypt OCTET STRING using use_etype,
                            req.padata.authenticator.subkey;
            else resp.enc-part := encrypt OCTET STRING
                                  using use_etype, tgt.key;
            send(resp);
    

    A.7.  KRB_TGS_REP 検証 (English)

            decode response into resp;
            if (resp.msg-type = KRB_ERROR) then
                    process_error(resp);
                    return;
            endif
            /* エラーが発生した場合は、応答を破棄し、 */
            /* 応答のセッション鍵を即座に 0 にする    */
            if (req.padata.authenticator.subkey)
                    unencrypted part of resp :=
                            decode of decrypt of resp.enc-part
                            using resp.enc-part.etype and subkey;
            else unencrypted part of resp :=
                            decode of decrypt of resp.enc-part
                            using resp.enc-part.etype and tgt's session key;
            if (common_as_rep_tgs_rep_checks fail) then
                    destroy resp.key;
                    return error;
            endif
            check authorization_data as necessary;
            save_for_later(ticket,session,client,server,times,flags);

    A.8.  Authenticator 生成 (English)

            body.authenticator-vno := authenticator vno; /* = 5 */
            body.cname, body.crealm := client name;
            if (supplying checksum) then
                    body.cksum := checksum;
            endif
            get system_time;
            body.ctime, body.cusec := system_time;
            if (selecting sub-session key) then
                    select sub-session key;
                    body.subkey := sub-session key;
            endif
            if (using sequence numbers) then
                    select initial sequence number;
                    body.seq-number := initial sequence;
            endif
    

    A.9.  KRB_AP_REQ 生成 (English)

            obtain ticket and session_key from cache;
            packet.pvno := protocol version; /* 5 */
            packet.msg-type := message type; /* KRB_AP_REQ */
            if (desired(MUTUAL_AUTHENTICATION)) then
                    set packet.ap-options.MUTUAL-REQUIRED;
            else
                    reset packet.ap-options.MUTUAL-REQUIRED;
            endif
            if (using session key for ticket) then
                    set packet.ap-options.USE-SESSION-KEY;
            else
                    reset packet.ap-options.USE-SESSION-KEY;
            endif
            packet.ticket := ticket; /* チケット */
            generate authenticator;
            encode authenticator into OCTET STRING;
            encrypt OCTET STRING into packet.authenticator
                                 using session_key;
    
    

    A.10.  KRB_AP_REQ 検証 (English)

            receive packet;
            if (packet.pvno != 5) then
                    either process using other protocol spec
                    or error_out(KRB_AP_ERR_BADVERSION);
            endif
            if (packet.msg-type != KRB_AP_REQ) then
                    error_out(KRB_AP_ERR_MSG_TYPE);
            endif
            if (packet.ticket.tkt_vno != 5) then
                    either process using other protocol spec
                    or error_out(KRB_AP_ERR_BADVERSION);
            endif
            if (packet.ap_options.USE-SESSION-KEY is set) then
                    retrieve session key from ticket-granting ticket for
                     packet.ticket.{sname,srealm,enc-part.etype};
            else
               retrieve service key for
               packet.ticket.{sname,srealm,enc-part.etype,enc-part.skvno};
            endif
            if (no_key_available) then
                    if (cannot_find_specified_skvno) then
                            error_out(KRB_AP_ERR_BADKEYVER);
                    else
                            error_out(KRB_AP_ERR_NOKEY);
                    endif
            endif
            decrypt packet.ticket.enc-part into decr_ticket
                                           using retrieved key;
            if (decryption_error()) then
                    error_out(KRB_AP_ERR_BAD_INTEGRITY);
            endif
            decrypt packet.authenticator into decr_authenticator
                    using decr_ticket.key;
            if (decryption_error()) then
                    error_out(KRB_AP_ERR_BAD_INTEGRITY);
            endif
            if (decr_authenticator.{cname,crealm} !=
                decr_ticket.{cname,crealm}) then
                    error_out(KRB_AP_ERR_BADMATCH);
            endif
            if (decr_ticket.caddr is present) then
                    if (sender_address(packet) is not in decr_ticket.caddr)
                            then error_out(KRB_AP_ERR_BADADDR);
                    endif
            elseif (application requires addresses) then
                    error_out(KRB_AP_ERR_BADADDR);
            endif
            if (not in_clock_skew(decr_authenticator.ctime,
                                  decr_authenticator.cusec)) then
                    error_out(KRB_AP_ERR_SKEW);
            endif
            if (repeated(decr_authenticator.{ctime,cusec,cname,crealm}))
                    then error_out(KRB_AP_ERR_REPEAT);
            endif
            save_identifier(decr_authenticator.{ctime,cusec,cname,crealm});
            get system_time;
            if ((decr_ticket.starttime-system_time > CLOCK_SKEW) or
                (decr_ticket.flags.INVALID is set)) then
                    /* まだ有効になっていません。 */
                    error_out(KRB_AP_ERR_TKT_NYV);
            endif
            if (system_time-decr_ticket.endtime > CLOCK_SKEW) then
                    error_out(KRB_AP_ERR_TKT_EXPIRED);
            endif
            /* 呼出側は、関係する詳細がないかどうか  */
            /* decr_ticket.flags チェックしなければならない */
            return(OK, decr_ticket, packet.ap_options.MUTUAL-REQUIRED);
    

    A.11.  KRB_AP_REP 生成 (English)

            packet.pvno := protocol version; /* 5 */
            packet.msg-type := message type; /* KRB_AP_REP */
            body.ctime := packet.ctime;
            body.cusec := packet.cusec;
            if (selecting sub-session key) then
                    select sub-session key;
                    body.subkey := sub-session key;
            endif
            if (using sequence numbers) then
                    select initial sequence number;
                    body.seq-number := initial sequence;
            endif
            encode body into OCTET STRING;
            select encryption type;
    
            encrypt OCTET STRING into packet.enc-part;
    

    A.12.  KRB_AP_REP 検証 (English)

            receive packet;
            if (packet.pvno != 5) then
                    either process using other protocol spec
                    or error_out(KRB_AP_ERR_BADVERSION);
            endif
            if (packet.msg-type != KRB_AP_REP) then
                    error_out(KRB_AP_ERR_MSG_TYPE);
            endif
            cleartext := decrypt(packet.enc-part)
                         using ticket's session key;
            if (decryption_error()) then
                    error_out(KRB_AP_ERR_BAD_INTEGRITY);
            endif
            if (cleartext.ctime != authenticator.ctime) then
                    error_out(KRB_AP_ERR_MUT_FAIL);
            endif
            if (cleartext.cusec != authenticator.cusec) then
                    error_out(KRB_AP_ERR_MUT_FAIL);
            endif
            if (cleartext.subkey is present) then
                    save cleartext.subkey for future use;
            endif
            if (cleartext.seq-number is present) then
                    save cleartext.seq-number for future verifications;
            endif
            return(AUTHENTICATION_SUCCEEDED);
    

    A.13.  KRB_SAFE 生成 (English)

            collect user data in buffer;
            /* パケットをアセンブルする: */
            packet.pvno := protocol version; /* 5 */
            packet.msg-type := message type; /* KRB_SAFE */
            body.user-data := buffer; /* DATA */
            if (using timestamp) then
                    get system_time;
                    body.timestamp, body.usec := system_time;
            endif
            if (using sequence numbers) then
                    body.seq-number := sequence number;
            endif
            body.s-address := sender host addresses;
            if (only one recipient) then
                    body.r-address := recipient host address;
            endif
            checksum.cksumtype := checksum type;
            compute checksum over body;
            checksum.checksum := checksum value; /* checksum.checksum */
            packet.cksum := checksum;
            packet.safe-body := body;
    
            receive packet;
            if (packet.pvno != 5) then
                   either process using other protocol spec
                    or error_out(KRB_AP_ERR_BADVERSION);
            endif
            if (packet.msg-type != KRB_SAFE) then
                    error_out(KRB_AP_ERR_MSG_TYPE);
            endif
            if (packet.checksum.cksumtype is not both collision-proof
                                                 and keyed) then
                    error_out(KRB_AP_ERR_INAPP_CKSUM);
            endif
            if (safe_priv_common_checks_ok(packet)) then
                    set computed_checksum := checksum(packet.body);
                    if (computed_checksum != packet.checksum) then
                            error_out(KRB_AP_ERR_MODIFIED);
                    endif
                    return (packet, PACKET_IS_GENUINE);
            else
                    return common_checks_error;
            endif
    

    A.15.  KRB_SAFE および KRB_PRIV の一般チェック (English)

            if (packet.s-address != O/S_sender(packet)) then
                /* 送信を要求していない送信者の O/S レポート */
                error_out(KRB_AP_ERR_BADADDR);
            endif
            if ((packet.r-address is present) and
                (packet.r-address != local_host_address)) then
                    /* 適切な場所に送信されていない */
                    error_out(KRB_AP_ERR_BADADDR);
            endif
            if (((packet.timestamp is present) and
                 (not in_clock_skew(packet.timestamp,packet.usec))) or
                (packet.timestamp is not present and timestamp expected))
                    then error_out(KRB_AP_ERR_SKEW);
            endif
            if (repeated(packet.timestamp,packet.usec,packet.s-address))
                    then error_out(KRB_AP_ERR_REPEAT);
            endif
            if (((packet.seq-number is present) and
                 ((not in_sequence(packet.seq-number)))) or
                (packet.seq-number is not present and sequence expected))
                    then error_out(KRB_AP_ERR_BADORDER);
            endif
            if (packet.timestamp not present and
                packet.seq-number not present) then
                    error_out(KRB_AP_ERR_MODIFIED);
            endif
            save_identifier(packet.{timestamp,usec,s-address},
                            sender_principal(packet));
            return PACKET_IS_OK;
    

    A.16.  KRB_PRIV 生成 (English)

            collect user data in buffer;
            /* パケットをアセンブルする: */
            packet.pvno := protocol version; /* 5 */
            packet.msg-type := message type; /* KRB_PRIV */
            packet.enc-part.etype := encryption type;
            body.user-data := buffer;
            if (using timestamp) then
                    get system_time;
                    body.timestamp, body.usec := system_time;
            endif
            if (using sequence numbers) then
                    body.seq-number := sequence number;
            endif
            body.s-address := sender host addresses;
            if (only one recipient) then
                    body.r-address := recipient host address;
            endif
            encode body into OCTET STRING;
            select encryption type;
            encrypt OCTET STRING into packet.enc-part.cipher;
    

    A.17.  KRB_PRIV 検証 (English)

            receive packet;
            if (packet.pvno != 5) then
                    either process using other protocol spec
                    or error_out(KRB_AP_ERR_BADVERSION);
            endif
            if (packet.msg-type != KRB_PRIV) then
                    error_out(KRB_AP_ERR_MSG_TYPE);
            endif
            cleartext := decrypt(packet.enc-part) using negotiated key;
            if (decryption_error()) then
                    error_out(KRB_AP_ERR_BAD_INTEGRITY);
            endif
            if (safe_priv_common_checks_ok(cleartext)) then
                return(cleartext.DATA, PACKET_IS_GENUINE_AND_UNMODIFIED);
            else
                    return common_checks_error;
            endif
    
    

    A.18.  KRB_CRED 生成 (English)

            invoke KRB_TGS; /* ピアに提供するチケットを取得する */
            /* パケットをアセンブルする: */
            packet.pvno := protocol version; /* 5 */
            packet.msg-type := message type; /* KRB_CRED */
            for (tickets[n] in tickets to be forwarded) do
                    packet.tickets[n] = tickets[n].ticket;
            done
            packet.enc-part.etype := encryption type;
            for (ticket[n] in tickets to be forwarded) do
                    body.ticket-info[n].key = tickets[n].session;
                    body.ticket-info[n].prealm = tickets[n].crealm;
                    body.ticket-info[n].pname = tickets[n].cname;
                    body.ticket-info[n].flags = tickets[n].flags;
                    body.ticket-info[n].authtime = tickets[n].authtime;
                    body.ticket-info[n].starttime = tickets[n].starttime;
                    body.ticket-info[n].endtime = tickets[n].endtime;
                    body.ticket-info[n].renew-till = tickets[n].renew-till;
                    body.ticket-info[n].srealm = tickets[n].srealm;
                    body.ticket-info[n].sname = tickets[n].sname;
                    body.ticket-info[n].caddr = tickets[n].caddr;
            done
            get system_time;
            body.timestamp, body.usec := system_time;
            if (using nonce) then
                    body.nonce := nonce;
            endif
            if (using s-address) then
                    body.s-address := sender host addresses;
            endif
            if (limited recipients) then
                    body.r-address := recipient host address;
            endif
            encode body into OCTET STRING;
            select encryption type;
            encrypt OCTET STRING into packet.enc-part.cipher
            using negotiated encryption key;
    

    A.19.  KRB_CRED 検証 (English)

            receive packet;
            if (packet.pvno != 5) then
                    either process using other protocol spec
                    or error_out(KRB_AP_ERR_BADVERSION);
            endif
            if (packet.msg-type != KRB_CRED) then
                    error_out(KRB_AP_ERR_MSG_TYPE);
            endif
            cleartext := decrypt(packet.enc-part) using negotiated key;
            if (decryption_error()) then
                    error_out(KRB_AP_ERR_BAD_INTEGRITY);
            endif
            if ((packet.r-address is present or required) and
               (packet.s-address != O/S_sender(packet)) then
                /* 送信を要求していない送信者の O/S レポート */
                error_out(KRB_AP_ERR_BADADDR);
            endif
            if ((packet.r-address is present) and
                (packet.r-address != local_host_address)) then
                    /* 適切な場所に送信されていない */
                    error_out(KRB_AP_ERR_BADADDR);
            endif
            if (not in_clock_skew(packet.timestamp,packet.usec)) then
                    error_out(KRB_AP_ERR_SKEW);
    
            endif
            if (repeated(packet.timestamp,packet.usec,packet.s-address))
                    then error_out(KRB_AP_ERR_REPEAT);
            endif
            if (packet.nonce is required or present) and
               (packet.nonce != expected-nonce) then
                    error_out(KRB_AP_ERR_MODIFIED);
            endif
            for (ticket[n] in tickets that were forwarded) do
                    save_for_later(ticket[n],key[n],principal[n],
                                   server[n],times[n],flags[n]);
            return

    A.20. KRB_ERROR 生成  (English)

            /* パケットをアセンブルする: */
            packet.pvno := protocol version; /* 5 */
            packet.msg-type := message type; /* KRB_ERROR */
            get system_time;
            packet.stime, packet.susec := system_time;
            packet.realm, packet.sname := server name;
            if (client time available) then
                    packet.ctime, packet.cusec := client_time;
            endif
            packet.error-code := error code;
            if (client name available) then
                    packet.cname, packet.crealm := client name;
            endif
            if (error text available) then
                    packet.e-text := error text;
            endif
            if (error data available) then
                    packet.e-data := error data;
            endif