Ejemplo n.º 1
0
static void
test_enctype(krb5_enctype enctype)
{
    krb5_error_code ret;
    krb5_keyblock keyblock;
    krb5_enc_data input;
    krb5_data output;
    krb5_crypto_iov iov[2];
    unsigned int dummy;
    size_t min_len, len;

    printf("Testing enctype %d\n", (int) enctype);
    x(krb5_c_encrypt_length(NULL, enctype, 0, &min_len));
    x(krb5_c_make_random_key(NULL, enctype, &keyblock));
    input.enctype = enctype;

    /* Try each length up to the minimum length. */
    for (len = 0; len <= min_len; len++) {
        input.ciphertext.data = calloc(len, 1);
        input.ciphertext.length = len;
        output.data = calloc(len, 1);
        output.length = len;

        /* Attempt a normal decryption. */
        ret = krb5_c_decrypt(NULL, &keyblock, 0, NULL, &input, &output);
        check_decrypt_result(ret, len, min_len);

        if (krb5_c_crypto_length(NULL, enctype, KRB5_CRYPTO_TYPE_HEADER,
                                 &dummy) == 0) {
            /* Attempt an IOV stream decryption. */
            iov[0].flags = KRB5_CRYPTO_TYPE_STREAM;
            iov[0].data = input.ciphertext;
            iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
            iov[1].data.data = NULL;
            iov[1].data.length = 0;
            ret = krb5_c_decrypt_iov(NULL, &keyblock, 0, NULL, iov, 2);
            check_decrypt_result(ret, len, min_len);
        }

        free(input.ciphertext.data);
        free(output.data);
    }
    krb5int_c_free_keyblock_contents (NULL, &keyblock);

}
Ejemplo n.º 2
0
uint32_t gp_init_creds_handle(uint32_t *min, struct gp_creds_handle **out)
{
    struct gp_creds_handle *handle;
    uint32_t ret_maj = 0;
    uint32_t ret_min = 0;
    int ret;

    handle = calloc(1, sizeof(struct gp_creds_handle));
    if (!handle) {
        ret_min = ENOMEM;
        ret_maj = GSS_S_FAILURE;
        goto done;
    }

    /* initialize key */
    ret = krb5_init_context(&handle->context);
    if (ret) {
        ret_min = ret;
        ret_maj = GSS_S_FAILURE;
        goto done;
    }

    ret = krb5_c_make_random_key(handle->context,
                                 GP_CREDS_HANDLE_KEY_ENCTYPE,
                                 &handle->key);
    if (ret) {
        ret_min = ret;
        ret_maj = GSS_S_FAILURE;
        goto done;
    }

    ret_maj = GSS_S_COMPLETE;
    ret_min = 0;

done:
    *min = ret_min;
    if (ret_maj) {
        gp_free_creds_handle(&handle);
    }
    *out = handle;

    return ret_maj;
}
Ejemplo n.º 3
0
static krb5_error_code
gen_session_key(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
                krb5_db_entry *server, krb5_keyblock *skey,
                const char **status)
{
    krb5_error_code retval;
    krb5_enctype useenctype = 0;

    /*
     * Some special care needs to be taken in the user-to-user
     * case, since we don't know what keytypes the application server
     * which is doing user-to-user authentication can support.  We
     * know that it at least must be able to support the encryption
     * type of the session key in the TGT, since otherwise it won't be
     * able to decrypt the U2U ticket!  So we use that in preference
     * to anything else.
     */
    if (req->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
        retval = get_2ndtkt_enctype(kdc_active_realm, req, &useenctype,
                                    status);
        if (retval != 0)
            goto cleanup;
    }
    if (useenctype == 0) {
        useenctype = select_session_keytype(kdc_active_realm, server,
                                            req->nktypes,
                                            req->ktype);
    }
    if (useenctype == 0) {
        /* unsupported ktype */
        *status = "BAD_ENCRYPTION_TYPE";
        retval = KRB5KDC_ERR_ETYPE_NOSUPP;
        goto cleanup;
    }
    retval = krb5_c_make_random_key(kdc_context, useenctype, skey);
    if (retval != 0) {
        /* random key failed */
        *status = "MAKE_RANDOM_KEY";
        goto cleanup;
    }
cleanup:
    return retval;
}
Ejemplo n.º 4
0
krb5_error_code KRB5_CALLCONV
krb5_random_key(krb5_context context, const krb5_encrypt_block *eblock,
		krb5_pointer ptr, krb5_keyblock **keyblock)
{
    krb5_keyblock *key;
    krb5_error_code ret;

    if ((key = (krb5_keyblock *) malloc(sizeof(krb5_keyblock))) == NULL)
	return(ENOMEM);

    if ((ret = krb5_c_make_random_key(context, eblock->crypto_entry, key))) {
	free(key);
	key = NULL;
    }

    *keyblock = key;

    return(ret);
}
Ejemplo n.º 5
0
/*ARGSUSED*/
krb5_error_code
process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
                krb5_data **response)
{
    krb5_keyblock * subkey = 0;
    krb5_kdc_req *request = 0;
    krb5_db_entry server;
    krb5_kdc_rep reply;
    krb5_enc_kdc_rep_part reply_encpart;
    krb5_ticket ticket_reply, *header_ticket = 0;
    int st_idx = 0;
    krb5_enc_tkt_part enc_tkt_reply;
    krb5_transited enc_tkt_transited;
    int newtransited = 0;
    krb5_error_code retval = 0;
    krb5_keyblock encrypting_key;
    int nprincs = 0;
    krb5_boolean more;
    krb5_timestamp kdc_time, authtime=0;
    krb5_keyblock session_key;
    krb5_timestamp until, rtime;
    krb5_keyblock *reply_key = NULL;
    krb5_keyblock *mkey_ptr;
    krb5_key_data  *server_key;
    char *cname = 0, *sname = 0, *altcname = 0;
    krb5_last_req_entry *nolrarray[2], nolrentry;
    krb5_enctype useenctype;
    int errcode, errcode2;
    register int i;
    int firstpass = 1;
    const char        *status = 0;
    krb5_enc_tkt_part *header_enc_tkt = NULL; /* ticket granting or evidence ticket */
    krb5_db_entry client, krbtgt;
    int c_nprincs = 0, k_nprincs = 0;
    krb5_pa_s4u_x509_user *s4u_x509_user = NULL; /* protocol transition request */
    krb5_authdata **kdc_issued_auth_data = NULL; /* auth data issued by KDC */
    unsigned int c_flags = 0, s_flags = 0;       /* client/server KDB flags */
    char *s4u_name = NULL;
    krb5_boolean is_referral, db_ref_done = FALSE;
    const char *emsg = NULL;
    krb5_data *tgs_1 =NULL, *server_1 = NULL;
    krb5_principal krbtgt_princ;
    krb5_kvno ticket_kvno = 0;
    struct kdc_request_state *state = NULL;
    krb5_pa_data *pa_tgs_req; /*points into request*/
    krb5_data scratch;

    session_key.contents = NULL;

    retval = decode_krb5_tgs_req(pkt, &request);
    if (retval)
        return retval;

    /*
     * setup_server_realm() sets up the global realm-specific data pointer.
     */
    if ((retval = setup_server_realm(request->server))) {
        krb5_free_kdc_req(kdc_context, request);
        return retval;
    }
    errcode = kdc_process_tgs_req(request, from, pkt, &header_ticket,
                                  &krbtgt, &k_nprincs, &subkey, &pa_tgs_req);
    if (header_ticket && header_ticket->enc_part2 &&
        (errcode2 = krb5_unparse_name(kdc_context,
                                      header_ticket->enc_part2->client,
                                      &cname))) {
        status = "UNPARSING CLIENT";
        errcode = errcode2;
        goto cleanup;
    }
    limit_string(cname);
    
    if (errcode) {
        status = "PROCESS_TGS";
        goto cleanup;
    }

    if (!header_ticket) {
        errcode = KRB5_NO_TKT_SUPPLIED;        /* XXX? */
        status="UNEXPECTED NULL in header_ticket";
        goto cleanup;
    }
    errcode = kdc_make_rstate(&state);
    if (errcode !=0) {
	status = "making state";
	goto cleanup;
    }
    scratch.length = pa_tgs_req->length;
    scratch.data = (char *) pa_tgs_req->contents;
    errcode = kdc_find_fast(&request, &scratch, subkey, header_ticket->enc_part2->session, state);
    if (errcode !=0) {
	status = "kdc_find_fast";
		goto cleanup;
    }


    /*
     * Pointer to the encrypted part of the header ticket, which may be
     * replaced to point to the encrypted part of the evidence ticket
     * if constrained delegation is used. This simplifies the number of
     * special cases for constrained delegation.
     */
    header_enc_tkt = header_ticket->enc_part2;
    
    /*
     * We've already dealt with the AP_REQ authentication, so we can
     * use header_ticket freely.  The encrypted part (if any) has been
     * decrypted with the session key.
     */

    /* XXX make sure server here has the proper realm...taken from AP_REQ
       header? */

    if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE)) {
        setflag(c_flags, KRB5_KDB_FLAG_CANONICALIZE);
        setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
    }

    db_ref_done = FALSE;
ref_tgt_again:
    nprincs = 1;
    if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
        status = "UNPARSING SERVER";
        goto cleanup;
    }
    limit_string(sname);

    errcode = krb5_db_get_principal_ext(kdc_context,
                                        request->server,
                                        s_flags,
                                        &server,
                                        &nprincs,
                                        &more);
    if (errcode) {
        status = "LOOKING_UP_SERVER";
        nprincs = 0;
        goto cleanup;
    }
tgt_again:
    if (more) {
        status = "NON_UNIQUE_PRINCIPAL";
        errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
        goto cleanup;
    } else if (nprincs != 1) {
        /*
         * might be a request for a TGT for some other realm; we
         * should do our best to find such a TGS in this db
         */
        if (firstpass ) {

            if ( krb5_is_tgs_principal(request->server) == TRUE) { /* Principal is a name of krb ticket service */
                if (krb5_princ_size(kdc_context, request->server) == 2) {

                    server_1 = krb5_princ_component(kdc_context, request->server, 1);
                    tgs_1 = krb5_princ_component(kdc_context, tgs_server, 1);

                    if (!tgs_1 || !data_eq(*server_1, *tgs_1)) {
                        krb5_db_free_principal(kdc_context, &server, nprincs);
                        find_alternate_tgs(request, &server, &more, &nprincs);
                        firstpass = 0;
                        goto tgt_again;
                    }
                }
                krb5_db_free_principal(kdc_context, &server, nprincs);
                status = "UNKNOWN_SERVER";
                errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
                goto cleanup;

            } else if ( db_ref_done == FALSE) {
                retval = prep_reprocess_req(request, &krbtgt_princ);
                if (!retval) {
                    krb5_free_principal(kdc_context, request->server);
                    retval = krb5_copy_principal(kdc_context, krbtgt_princ, &(request->server));
                    if (!retval) {
                        db_ref_done = TRUE;
                        if (sname != NULL)
                            free(sname);
                        goto ref_tgt_again;
                    }
                }
            }
        }

        krb5_db_free_principal(kdc_context, &server, nprincs);
        status = "UNKNOWN_SERVER";
        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
        goto cleanup;
    }

    if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) {
        status = "TIME_OF_DAY";
        goto cleanup;
    }
    
    if ((retval = validate_tgs_request(request, server, header_ticket,
                                       kdc_time, &status))) {
    if (!status)
        status = "UNKNOWN_REASON";
        errcode = retval + ERROR_TABLE_BASE_krb5;
        goto cleanup;
    }

    if (!is_local_principal(header_enc_tkt->client))
        setflag(c_flags, KRB5_KDB_FLAG_CROSS_REALM);

    is_referral = krb5_is_tgs_principal(server.princ) &&
        !krb5_principal_compare(kdc_context, tgs_server, server.princ);

    /* Check for protocol transition */
    errcode = kdc_process_s4u2self_req(kdc_context,
				       request,
				       header_enc_tkt->client,
                                       &server,
				       subkey,
				       header_enc_tkt->session,
				       kdc_time,
                                       &s4u_x509_user,
				       &client,
				       &c_nprincs,
				       &status);
    if (errcode)
        goto cleanup;
    if (s4u_x509_user != NULL)
        setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);

    /*
     * We pick the session keytype here....
     * 
     * Some special care needs to be taken in the user-to-user
     * case, since we don't know what keytypes the application server
     * which is doing user-to-user authentication can support.  We
     * know that it at least must be able to support the encryption
     * type of the session key in the TGT, since otherwise it won't be
     * able to decrypt the U2U ticket!  So we use that in preference
     * to anything else.
     */
    useenctype = 0;
    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY |
                        KDC_OPT_CNAME_IN_ADDL_TKT)) {
        krb5_keyblock *        st_sealing_key;
        krb5_kvno       st_srv_kvno;
        krb5_enctype    etype;
        krb5_db_entry    st_client;
        int             st_nprincs = 0;

        /*
         * Get the key for the second ticket, and decrypt it.
         */
        if ((errcode = kdc_get_server_key(request->second_ticket[st_idx],
                                          c_flags,
                                          TRUE, /* match_enctype */
                                          &st_client,
                                          &st_nprincs,
                                          &st_sealing_key,
                                          &st_srv_kvno))) {
            status = "2ND_TKT_SERVER";
            goto cleanup;
        }
        errcode = krb5_decrypt_tkt_part(kdc_context, st_sealing_key,
                                    request->second_ticket[st_idx]);
        krb5_free_keyblock(kdc_context, st_sealing_key);
        if (errcode) {
            status = "2ND_TKT_DECRYPT";
            krb5_db_free_principal(kdc_context, &st_client, st_nprincs);
            goto cleanup;
        }

        etype = request->second_ticket[st_idx]->enc_part2->session->enctype;
        if (!krb5_c_valid_enctype(etype)) {
            status = "BAD_ETYPE_IN_2ND_TKT";
            errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
            krb5_db_free_principal(kdc_context, &st_client, st_nprincs);
            goto cleanup;
        }

        for (i = 0; i < request->nktypes; i++) {
            if (request->ktype[i] == etype) {
                useenctype = etype;
                break;
            }
        }

        if (isflagset(request->kdc_options, KDC_OPT_CNAME_IN_ADDL_TKT)) {
            /* Do constrained delegation protocol and authorization checks */
            errcode = kdc_process_s4u2proxy_req(kdc_context,
                                                request,
                                                request->second_ticket[st_idx]->enc_part2,
                                                &st_client,
                                                header_ticket->enc_part2->client,
                                                request->server,
                                                &status);
            if (errcode)
                goto cleanup;

            setflag(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);

            assert(krb5_is_tgs_principal(header_ticket->server));

            /* From now on, use evidence ticket as header ticket */
            header_enc_tkt = request->second_ticket[st_idx]->enc_part2;

            assert(c_nprincs == 0); /* assured by kdc_process_s4u2self_req() */

            client = st_client;
            c_nprincs = st_nprincs;
        } else {
            /* "client" is not used for user2user */
            krb5_db_free_principal(kdc_context, &st_client, st_nprincs);
        }
    }

    /*
     * Select the keytype for the ticket session key.
     */
    if ((useenctype == 0) &&
        (useenctype = select_session_keytype(kdc_context, &server,
        request->nktypes,
        request->ktype)) == 0) {
        /* unsupported ktype */
        status = "BAD_ENCRYPTION_TYPE";
        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
        goto cleanup;
    }
    
    errcode = krb5_c_make_random_key(kdc_context, useenctype, &session_key);

    if (errcode) {
        /* random key failed */
        status = "RANDOM_KEY_FAILED";
        goto cleanup;
    }

    authtime = header_enc_tkt->times.authtime;

    if (is_referral)
        ticket_reply.server = server.princ;
    else
        ticket_reply.server = request->server; /* XXX careful for realm... */

    enc_tkt_reply.flags = 0;
    enc_tkt_reply.times.starttime = 0;

    if (isflagset(server.attributes, KRB5_KDB_OK_AS_DELEGATE))
        setflag(enc_tkt_reply.flags, TKT_FLG_OK_AS_DELEGATE);

    /*
     * Fix header_ticket's starttime; if it's zero, fill in the
     * authtime's value.
     */
    if (!(header_enc_tkt->times.starttime))
        header_enc_tkt->times.starttime = header_enc_tkt->times.authtime;

    /* don't use new addresses unless forwarded, see below */

    enc_tkt_reply.caddrs = header_enc_tkt->caddrs;
    /* noaddrarray[0] = 0; */
    reply_encpart.caddrs = 0;/* optional...don't put it in */
    reply_encpart.enc_padata = NULL;

    /* It should be noted that local policy may affect the  */
    /* processing of any of these flags.  For example, some */
    /* realms may refuse to issue renewable tickets         */

    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE)) {
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);

        if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
            /*
             * If S4U2Self principal is not forwardable, then mark ticket as
             * unforwardable. This behaviour matches Windows, but it is
             * different to the MIT AS-REQ path, which returns an error
             * (KDC_ERR_POLICY) if forwardable tickets cannot be issued.
             *
             * Consider this block the S4U2Self equivalent to
             * validate_forwardable().
             */
            if (c_nprincs &&
                isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
                clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
            /*
             * OK_TO_AUTH_AS_DELEGATE must be set on the service requesting
             * S4U2Self in order for forwardable tickets to be returned.
             */
            else if (!is_referral &&
                !isflagset(server.attributes, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
                clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
        }
    }

    if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) {
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);

        /* include new addresses in ticket & reply */

        enc_tkt_reply.caddrs = request->addresses;
        reply_encpart.caddrs = request->addresses;
    }
    if (isflagset(header_enc_tkt->flags, TKT_FLG_FORWARDED))
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);

    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE))
        setflag(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);

    if (isflagset(request->kdc_options, KDC_OPT_PROXY)) {
        setflag(enc_tkt_reply.flags, TKT_FLG_PROXY);

        /* include new addresses in ticket & reply */

        enc_tkt_reply.caddrs = request->addresses;
        reply_encpart.caddrs = request->addresses;
    }

    if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
        setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);

    if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
        setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
        setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
        enc_tkt_reply.times.starttime = request->from;
    } else
        enc_tkt_reply.times.starttime = kdc_time;

    if (isflagset(request->kdc_options, KDC_OPT_VALIDATE)) {
        assert(isflagset(c_flags, KRB5_KDB_FLAGS_S4U) == 0);
        /* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
           to the caller */
        ticket_reply = *(header_ticket);
        enc_tkt_reply = *(header_ticket->enc_part2);
        clear(enc_tkt_reply.flags, TKT_FLG_INVALID);
    }

    if (isflagset(request->kdc_options, KDC_OPT_RENEW)) {
        krb5_deltat old_life;

        assert(isflagset(c_flags, KRB5_KDB_FLAGS_S4U) == 0);
        /* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
           to the caller */
        ticket_reply = *(header_ticket);
        enc_tkt_reply = *(header_ticket->enc_part2);

        old_life = enc_tkt_reply.times.endtime - enc_tkt_reply.times.starttime;

        enc_tkt_reply.times.starttime = kdc_time;
        enc_tkt_reply.times.endtime =
            min(header_ticket->enc_part2->times.renew_till,
                kdc_time + old_life);
    } else {
        /* not a renew request */
        enc_tkt_reply.times.starttime = kdc_time;
        until = (request->till == 0) ? kdc_infinity : request->till;
        enc_tkt_reply.times.endtime =
            min(until, min(enc_tkt_reply.times.starttime + server.max_life,
               min(enc_tkt_reply.times.starttime + max_life_for_realm,
                   header_enc_tkt->times.endtime)));
        if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
            (enc_tkt_reply.times.endtime < request->till) &&
            isflagset(header_enc_tkt->flags, TKT_FLG_RENEWABLE)) {
            setflag(request->kdc_options, KDC_OPT_RENEWABLE);
            request->rtime =
                min(request->till, header_enc_tkt->times.renew_till);
        }
    }
    rtime = (request->rtime == 0) ? kdc_infinity : request->rtime;

    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) {
        /* already checked above in policy check to reject request for a
           renewable ticket using a non-renewable ticket */
        setflag(enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
        enc_tkt_reply.times.renew_till =
                        min(rtime,
                            min(header_enc_tkt->times.renew_till,
                                enc_tkt_reply.times.starttime +
                                min(server.max_renewable_life,
                                max_renewable_life_for_realm)));
    } else {
        enc_tkt_reply.times.renew_till = 0;
    }
    
    /*
     * Set authtime to be the same as header_ticket's
     */
    enc_tkt_reply.times.authtime = header_enc_tkt->times.authtime;
    
    /*
     * Propagate the preauthentication flags through to the returned ticket.
     */
    if (isflagset(header_enc_tkt->flags, TKT_FLG_PRE_AUTH))
        setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH);

    if (isflagset(header_enc_tkt->flags, TKT_FLG_HW_AUTH))
        setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH);
    
    /* starttime is optional, and treated as authtime if not present.
       so we can nuke it if it matches */
    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
        enc_tkt_reply.times.starttime = 0;

    if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
        errcode = krb5_unparse_name(kdc_context, s4u_x509_user->user_id.user, &s4u_name);
    } else if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
        errcode = krb5_unparse_name(kdc_context, header_enc_tkt->client, &s4u_name);
    } else {
        errcode = 0;
    }
    if (errcode) {
        status = "UNPARSING S4U CLIENT";
        goto cleanup;
    }

    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
        krb5_enc_tkt_part *t2enc = request->second_ticket[st_idx]->enc_part2;
        encrypting_key = *(t2enc->session);
    } else {
        /*
         * Find the server key
         */
        if ((errcode = krb5_dbe_find_enctype(kdc_context, &server,
                             -1, /* ignore keytype */
                                             -1, /* Ignore salttype */
                                             0,/* Get highest kvno */
                                             &server_key))) {
            status = "FINDING_SERVER_KEY";
            goto cleanup;
        }

        if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, &server,
                                          &mkey_ptr))) {
            krb5_keylist_node *tmp_mkey_list;
            /* try refreshing master key list */
            /* XXX it would nice if we had the mkvno here for optimization */
            if (krb5_db_fetch_mkey_list(kdc_context, master_princ,
                                        &master_keyblock, 0, &tmp_mkey_list) == 0) {
                krb5_dbe_free_key_list(kdc_context, master_keylist);
                master_keylist = tmp_mkey_list;
                if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist,
                                                  &server, &mkey_ptr))) {
                    status = "FINDING_MASTER_KEY";
                    goto cleanup;
                }
            } else {
                status = "FINDING_MASTER_KEY";
                goto cleanup;
            }
        }

        /* convert server.key into a real key (it may be encrypted
         *        in the database) */
        if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context,
                                                   mkey_ptr,
                                                   server_key, &encrypting_key,
                                                   NULL))) {
            status = "DECRYPT_SERVER_KEY";
            goto cleanup;
        }
    }

    if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
        /*
         * Don't allow authorization data to be disabled if constrained
         * delegation is requested. We don't want to deny the server
         * the ability to validate that delegation was used.
         */
        clear(server.attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED);
    }
    if (isflagset(server.attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED) == 0) {
        /*
         * If we are not doing protocol transition/constrained delegation
         * and there was no authorization data included, try to lookup
         * the client principal as it may be mapped to a local account.
         *
         * Always validate authorization data for constrained delegation
         * because we must validate the KDC signatures.
         */
        if (!isflagset(c_flags, KRB5_KDB_FLAGS_S4U) &&
            header_enc_tkt->authorization_data == NULL) {

            /* Generate authorization data so we can include it in ticket */
            setflag(c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
            /* Map principals from foreign (possibly non-AD) realms */
            setflag(c_flags, KRB5_KDB_FLAG_MAP_PRINCIPALS);

            assert(c_nprincs == 0); /* should not have been looked up already */

            c_nprincs = 1;
            errcode = krb5_db_get_principal_ext(kdc_context,
                                                header_enc_tkt->client,
                                                c_flags,
                                                &client,
                                                &c_nprincs,
                                                &more);
            /*
             * We can ignore errors because the principal may be a
             * valid cross-realm principal for which we have no local
             * mapping. But we do want to check that at most one entry
             * was returned.
             */
            if (errcode == 0 && (more || c_nprincs > 1)) {
                errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
                goto cleanup;
            } else if (errcode) {
                c_nprincs = 0;
            }
        }
    }

    enc_tkt_reply.authorization_data = NULL;

    if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
        !isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM))
        enc_tkt_reply.client = s4u_x509_user->user_id.user;
    else
        enc_tkt_reply.client = header_enc_tkt->client;

    enc_tkt_reply.session = &session_key;
    enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
    enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */

    errcode = handle_authdata(kdc_context,
                              c_flags,
                              (c_nprincs != 0) ? &client : NULL,
                              &server,
                              (k_nprincs != 0) ? &krbtgt : NULL,
                              subkey != NULL ? subkey :
                              header_ticket->enc_part2->session,
                              &encrypting_key, /* U2U or server key */
                              pkt,
                              request,
                              s4u_x509_user ?
				s4u_x509_user->user_id.user : NULL,
                              header_enc_tkt,
                              &enc_tkt_reply);
    if (errcode) {
        krb5_klog_syslog(LOG_INFO, "TGS_REQ : handle_authdata (%d)", errcode);
        status = "HANDLE_AUTHDATA";
        goto cleanup;
    }

    if (is_referral && isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
        errcode = return_svr_referral_data(kdc_context,
                                           &server, &reply_encpart);
        if (errcode) {
            status = "KDC_RETURN_ENC_PADATA";
            goto cleanup;
        }
    }

    /*
     * Only add the realm of the presented tgt to the transited list if 
     * it is different than the local realm (cross-realm) and it is different
     * than the realm of the client (since the realm of the client is already
     * implicitly part of the transited list and should not be explicitly
     * listed).
     */

    /* realm compare is like strcmp, but knows how to deal with these args */
    if (realm_compare(header_ticket->server, tgs_server) ||
        realm_compare(header_ticket->server, enc_tkt_reply.client)) {
        /* tgt issued by local realm or issued by realm of client */
        enc_tkt_reply.transited = header_enc_tkt->transited;
    } else {
        /* tgt issued by some other realm and not the realm of the client */
        /* assemble new transited field into allocated storage */
        if (header_enc_tkt->transited.tr_type !=
            KRB5_DOMAIN_X500_COMPRESS) {
            status = "BAD_TRTYPE";
            errcode = KRB5KDC_ERR_TRTYPE_NOSUPP;
            goto cleanup;
        }
        enc_tkt_transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
        enc_tkt_transited.magic = 0;
        enc_tkt_transited.tr_contents.magic = 0;
        enc_tkt_transited.tr_contents.data = 0;
        enc_tkt_transited.tr_contents.length = 0;
        enc_tkt_reply.transited = enc_tkt_transited;
        if ((errcode =
            add_to_transited(&header_enc_tkt->transited.tr_contents,
                             &enc_tkt_reply.transited.tr_contents,
                             header_ticket->server,
                             enc_tkt_reply.client,
                             request->server))) {
                                 status = "ADD_TR_FAIL";
                                 goto cleanup;
        }
        newtransited = 1;
    }
    if (isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM)) {
        errcode = validate_transit_path(kdc_context, header_enc_tkt->client,
        &server,
        (k_nprincs != 0) ? &krbtgt : NULL);
        if (errcode) {
            status = "NON_TRANSITIVE";
            goto cleanup;
        }
    }
    if (!isflagset (request->kdc_options, KDC_OPT_DISABLE_TRANSITED_CHECK)) {
        unsigned int tlen;
        char *tdots;

        errcode = kdc_check_transited_list (kdc_context,
                                            &enc_tkt_reply.transited.tr_contents,
                                            krb5_princ_realm (kdc_context, header_enc_tkt->client),
                                            krb5_princ_realm (kdc_context, request->server));
        tlen = enc_tkt_reply.transited.tr_contents.length;
        tdots = tlen > 125 ? "..." : "";
        tlen = tlen > 125 ? 125 : tlen;

        if (errcode == 0) {
            setflag (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED);
        } else if (errcode == KRB5KRB_AP_ERR_ILL_CR_TKT)
            krb5_klog_syslog (LOG_INFO,
                              "bad realm transit path from '%s' to '%s' "
                              "via '%.*s%s'",
                              cname ? cname : "<unknown client>",
                              sname ? sname : "<unknown server>",
                              tlen,
                              enc_tkt_reply.transited.tr_contents.data,
                              tdots);
        else {
            emsg = krb5_get_error_message(kdc_context, errcode);
            krb5_klog_syslog (LOG_ERR,
                              "unexpected error checking transit from "
                              "'%s' to '%s' via '%.*s%s': %s",
                              cname ? cname : "<unknown client>",
                              sname ? sname : "<unknown server>",
                              tlen,
                              enc_tkt_reply.transited.tr_contents.data,
                              tdots, emsg);
            krb5_free_error_message(kdc_context, emsg);
            emsg = NULL;
        }
    } else
        krb5_klog_syslog (LOG_INFO, "not checking transit path");
    if (reject_bad_transit
        && !isflagset (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED)) {
        errcode = KRB5KDC_ERR_POLICY;
        status = "BAD_TRANSIT";
        goto cleanup;
    }

    ticket_reply.enc_part2 = &enc_tkt_reply;

    /*
     * If we are doing user-to-user authentication, then make sure
     * that the client for the second ticket matches the request
     * server, and then encrypt the ticket using the session key of
     * the second ticket.
     */
    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
        /*
         * Make sure the client for the second ticket matches
         * requested server.
         */
        krb5_enc_tkt_part *t2enc = request->second_ticket[st_idx]->enc_part2;
        krb5_principal client2 = t2enc->client;
        if (!krb5_principal_compare(kdc_context, request->server, client2)) {
            if ((errcode = krb5_unparse_name(kdc_context, client2, &altcname)))
                altcname = 0;
            if (altcname != NULL)
                limit_string(altcname);

            errcode = KRB5KDC_ERR_SERVER_NOMATCH;
            status = "2ND_TKT_MISMATCH";
            goto cleanup;
        }

        ticket_kvno = 0;
        ticket_reply.enc_part.enctype = t2enc->session->enctype;
        st_idx++;
    } else {
        ticket_kvno = server_key->key_data_kvno;
    }

    errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key,
                    &ticket_reply);
    if (!isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY))
        krb5_free_keyblock_contents(kdc_context, &encrypting_key);
    if (errcode) {
        status = "TKT_ENCRYPT";
        goto cleanup;
    }
    ticket_reply.enc_part.kvno = ticket_kvno;
    /* Start assembling the response */
    reply.msg_type = KRB5_TGS_REP;
    reply.padata = 0;/* always */
    if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
        find_pa_data(request->padata, KRB5_PADATA_S4U_X509_USER) != NULL) {
        errcode = kdc_make_s4u2self_rep(kdc_context,
                                        subkey,
                                        header_ticket->enc_part2->session,
                                        s4u_x509_user,
                                        &reply,
                                        &reply_encpart);
        if (errcode) {
            status = "KDC_RETURN_S4U2SELF_PADATA";
            goto cleanup;
        }
    }

    reply.client = enc_tkt_reply.client;
    reply.enc_part.kvno = 0;/* We are using the session key */
    reply.ticket = &ticket_reply;

    reply_encpart.session = &session_key;
    reply_encpart.nonce = request->nonce;

    /* copy the time fields EXCEPT for authtime; its location
       is used for ktime */
    reply_encpart.times = enc_tkt_reply.times;
    reply_encpart.times.authtime = header_enc_tkt->times.authtime;

    /* starttime is optional, and treated as authtime if not present.
       so we can nuke it if it matches */
    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
        enc_tkt_reply.times.starttime = 0;

    nolrentry.lr_type = KRB5_LRQ_NONE;
    nolrentry.value = 0;
    nolrarray[0] = &nolrentry;
    nolrarray[1] = 0;
    reply_encpart.last_req = nolrarray;        /* not available for TGS reqs */
    reply_encpart.key_exp = 0;/* ditto */
    reply_encpart.flags = enc_tkt_reply.flags;
    reply_encpart.server = ticket_reply.server;
    
    /* use the session key in the ticket, unless there's a subsession key
       in the AP_REQ */

    reply.enc_part.enctype = subkey ? subkey->enctype :
    header_ticket->enc_part2->session->enctype;
    errcode  = kdc_fast_response_handle_padata(state, request, &reply,
					       subkey?subkey->enctype:header_ticket->enc_part2->session->enctype);
    if (errcode !=0 ) {
	status = "Preparing FAST padata";
	goto cleanup;
    }
    errcode =kdc_fast_handle_reply_key(state, subkey?subkey:header_ticket->enc_part2->session, &reply_key);
    if (errcode) {
      status  = "generating reply key";
      goto cleanup;
    }
            errcode = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart,
                  subkey ? 1 : 0,
					  reply_key,
                  &reply, response);
    if (errcode) {
        status = "ENCODE_KDC_REP";
    } else {
        status = "ISSUE";
    }

    memset(ticket_reply.enc_part.ciphertext.data, 0,
           ticket_reply.enc_part.ciphertext.length);
    free(ticket_reply.enc_part.ciphertext.data);
    /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
       can use them in raw form if needed.  But, we don't... */
    memset(reply.enc_part.ciphertext.data, 0,
           reply.enc_part.ciphertext.length);
    free(reply.enc_part.ciphertext.data);
    
cleanup:
    assert(status != NULL);
    if (reply_key)
      krb5_free_keyblock(kdc_context, reply_key);
    if (errcode)
        emsg = krb5_get_error_message (kdc_context, errcode);
    log_tgs_req(from, request, &reply, cname, sname, altcname, authtime,
                c_flags, s4u_name, status, errcode, emsg);
    if (errcode) {
        krb5_free_error_message (kdc_context, emsg);
        emsg = NULL;
    }

    if (errcode) {
        int got_err = 0;
        if (status == 0) {
            status = krb5_get_error_message (kdc_context, errcode);
            got_err = 1;
        }
        errcode -= ERROR_TABLE_BASE_krb5;
        if (errcode < 0 || errcode > 128)
            errcode = KRB_ERR_GENERIC;

        retval = prepare_error_tgs(state, request, header_ticket, errcode,
        nprincs ? server.princ : NULL,
                   response, status);
        if (got_err) {
            krb5_free_error_message (kdc_context, status);
            status = 0;
        }
    }
    
    if (header_ticket != NULL)
        krb5_free_ticket(kdc_context, header_ticket);
    if (request != NULL)
        krb5_free_kdc_req(kdc_context, request);
    if (state)
	kdc_free_rstate(state);
    if (cname != NULL)
        free(cname);
    if (sname != NULL)
        free(sname);
    if (nprincs != 0)
        krb5_db_free_principal(kdc_context, &server, 1);
    if (session_key.contents != NULL)
        krb5_free_keyblock_contents(kdc_context, &session_key);
    if (newtransited)
        free(enc_tkt_reply.transited.tr_contents.data);
    if (k_nprincs)
        krb5_db_free_principal(kdc_context, &krbtgt, k_nprincs);
    if (c_nprincs)
        krb5_db_free_principal(kdc_context, &client, c_nprincs);
    if (s4u_x509_user != NULL)
        krb5_free_pa_s4u_x509_user(kdc_context, s4u_x509_user);
    if (kdc_issued_auth_data != NULL)
        krb5_free_authdata(kdc_context, kdc_issued_auth_data);
    if (s4u_name != NULL)
        free(s4u_name);
    if (subkey != NULL)
        krb5_free_keyblock(kdc_context, subkey);
    if (reply.padata)
        krb5_free_pa_data(kdc_context, reply.padata);
    if (reply_encpart.enc_padata)
        krb5_free_pa_data(kdc_context, reply_encpart.enc_padata);

    return retval;
}
Ejemplo n.º 6
0
static krb5_error_code
setup_sam(void)
{
    return krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_MD5, &psr_key);
}
Ejemplo n.º 7
0
int create_keys(krb5_context krbctx,
                krb5_principal princ,
                char *password,
                const char *enctypes_string,
                struct keys_container *keys,
                char **err_msg)
{
    struct krb_key_salt *ksdata;
    krb5_error_code krberr;
    krb5_data key_password;
    krb5_data *realm = NULL;
    int i, nkeys;
    int ret;

    *err_msg = NULL;

    ret = prep_ksdata(krbctx, enctypes_string, keys, err_msg);
    if (ret == 0) return 0;

    ksdata = keys->ksdata;
    nkeys = keys->nkeys;

    if (password) {
        key_password.data = password;
        key_password.length = strlen(password);

        realm = krb5_princ_realm(krbctx, princ);
    }

    for (i = 0; i < nkeys; i++) {
        krb5_data *salt;

        if (!password) {
            /* cool, random keys */
            krberr = krb5_c_make_random_key(krbctx,
                                            ksdata[i].enctype,
                                            &ksdata[i].key);
            if (krberr) {
                *err_msg = _("Failed to create random key!\n");
                return 0;
            }
            /* set the salt to NO_SALT as the key was random */
            ksdata[i].salttype = NO_SALT;
            continue;
        }

        /* Make keys using password and required salt */
        switch (ksdata[i].salttype) {
        case KRB5_KDB_SALTTYPE_ONLYREALM:
            krberr = krb5_copy_data(krbctx, realm, &salt);
            if (krberr) {
                *err_msg = _("Failed to create key!\n");
                return 0;
            }

            ksdata[i].salt.length = salt->length;
            ksdata[i].salt.data = malloc(salt->length);
            if (!ksdata[i].salt.data) {
                *err_msg = _("Out of memory!\n");
                return 0;
            }
            memcpy(ksdata[i].salt.data, salt->data, salt->length);
            krb5_free_data(krbctx, salt);
            break;

        case KRB5_KDB_SALTTYPE_NOREALM:
            krberr = ipa_krb5_principal2salt_norealm(krbctx, princ,
                                                     &ksdata[i].salt);
            if (krberr) {
                *err_msg = _("Failed to create key!\n");
                return 0;
            }
            break;

        case KRB5_KDB_SALTTYPE_NORMAL:
            krberr = krb5_principal2salt(krbctx, princ, &ksdata[i].salt);
            if (krberr) {
                *err_msg = _("Failed to create key!\n");
                return 0;
            }
            break;

        /* no KRB5_KDB_SALTTYPE_V4, we do not support krb v4 */

        case KRB5_KDB_SALTTYPE_AFS3:
            /* Comment from MIT sources:
             * * Why do we do this? Well, the afs_mit_string_to_key
             * * needs to use strlen, and the realm is not NULL
             * * terminated....
             */
            ksdata[i].salt.data = (char *)malloc(realm->length + 1);
            if (NULL == ksdata[i].salt.data) {
                *err_msg = _("Out of memory!\n");
                return 0;
            }
            memcpy((char *)ksdata[i].salt.data,
                   (char *)realm->data, realm->length);
            ksdata[i].salt.data[realm->length] = '\0';
            /* AFS uses a special length (UGLY) */
            ksdata[i].salt.length = SALT_TYPE_AFS_LENGTH;
            break;

        default:
            *err_msg = _("Bad or unsupported salt type.\n");
/* FIXME:
            fprintf(stderr, _("Bad or unsupported salt type (%d)!\n"),
                ksdata[i].salttype);
*/
            return 0;
        }

        krberr = krb5_c_string_to_key(krbctx,
                                      ksdata[i].enctype,
                                      &key_password,
                                      &ksdata[i].salt,
                                      &ksdata[i].key);
        if (krberr) {
            *err_msg = _("Failed to create key!\n");
            return 0;
        }

        /* set back salt length to real value if AFS3 */
        if (ksdata[i].salttype == KRB5_KDB_SALTTYPE_AFS3) {
            ksdata[i].salt.length = realm->length;
        }
    }

    return nkeys;
}
Ejemplo n.º 8
0
/*ARGSUSED*/
void
process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
               const krb5_fulladdr *from, kdc_realm_t *kdc_active_realm,
               verto_ctx *vctx, loop_respond_fn respond, void *arg)
{
    krb5_error_code errcode;
    krb5_timestamp rtime;
    unsigned int s_flags = 0;
    krb5_data encoded_req_body;
    krb5_enctype useenctype;
    struct as_req_state *state;

    state = k5alloc(sizeof(*state), &errcode);
    if (state == NULL) {
        (*respond)(arg, errcode, NULL);
        return;
    }
    state->respond = respond;
    state->arg = arg;
    state->request = request;
    state->req_pkt = req_pkt;
    state->from = from;
    state->active_realm = kdc_active_realm;

    errcode = kdc_make_rstate(kdc_active_realm, &state->rstate);
    if (errcode != 0) {
        (*respond)(arg, errcode, NULL);
        return;
    }
    if (state->request->msg_type != KRB5_AS_REQ) {
        state->status = "msg_type mismatch";
        errcode = KRB5_BADMSGTYPE;
        goto errout;
    }
    if (fetch_asn1_field((unsigned char *) req_pkt->data,
                         1, 4, &encoded_req_body) != 0) {
        errcode = ASN1_BAD_ID;
        state->status = "Finding req_body";
        goto errout;
    }
    errcode = kdc_find_fast(&state->request, &encoded_req_body, NULL, NULL,
                            state->rstate, &state->inner_body);
    if (errcode) {
        state->status = "error decoding FAST";
        goto errout;
    }
    if (state->inner_body == NULL) {
        /* Not a FAST request; copy the encoded request body. */
        errcode = krb5_copy_data(kdc_context, &encoded_req_body,
                                 &state->inner_body);
        if (errcode) {
            state->status = "storing req body";
            goto errout;
        }
    }
    state->rock.request = state->request;
    state->rock.inner_body = state->inner_body;
    state->rock.rstate = state->rstate;
    state->rock.vctx = vctx;
    if (!state->request->client) {
        state->status = "NULL_CLIENT";
        errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
        goto errout;
    }
    if ((errcode = krb5_unparse_name(kdc_context,
                                     state->request->client,
                                     &state->cname))) {
        state->status = "UNPARSING_CLIENT";
        goto errout;
    }
    limit_string(state->cname);
    if (!state->request->server) {
        state->status = "NULL_SERVER";
        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
        goto errout;
    }
    if ((errcode = krb5_unparse_name(kdc_context,
                                     state->request->server,
                                     &state->sname))) {
        state->status = "UNPARSING_SERVER";
        goto errout;
    }
    limit_string(state->sname);

    /*
     * We set KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY as a hint
     * to the backend to return naming information in lieu
     * of cross realm TGS entries.
     */
    setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY);
    /*
     * Note that according to the referrals draft we should
     * always canonicalize enterprise principal names.
     */
    if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) ||
        state->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
        setflag(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE);
        setflag(state->c_flags, KRB5_KDB_FLAG_ALIAS_OK);
    }
    if (include_pac_p(kdc_context, state->request)) {
        setflag(state->c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
    }
    errcode = krb5_db_get_principal(kdc_context, state->request->client,
                                    state->c_flags, &state->client);
    if (errcode == KRB5_KDB_CANTLOCK_DB)
        errcode = KRB5KDC_ERR_SVC_UNAVAILABLE;
    if (errcode == KRB5_KDB_NOENTRY) {
        state->status = "CLIENT_NOT_FOUND";
        if (vague_errors)
            errcode = KRB5KRB_ERR_GENERIC;
        else
            errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
        goto errout;
    } else if (errcode) {
        state->status = "LOOKING_UP_CLIENT";
        goto errout;
    }
    state->rock.client = state->client;

    /*
     * If the backend returned a principal that is not in the local
     * realm, then we need to refer the client to that realm.
     */
    if (!is_local_principal(kdc_active_realm, state->client->princ)) {
        /* Entry is a referral to another realm */
        state->status = "REFERRAL";
        errcode = KRB5KDC_ERR_WRONG_REALM;
        goto errout;
    }

    s_flags = 0;
    setflag(s_flags, KRB5_KDB_FLAG_ALIAS_OK);
    if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
        setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
    }
    errcode = krb5_db_get_principal(kdc_context, state->request->server,
                                    s_flags, &state->server);
    if (errcode == KRB5_KDB_CANTLOCK_DB)
        errcode = KRB5KDC_ERR_SVC_UNAVAILABLE;
    if (errcode == KRB5_KDB_NOENTRY) {
        state->status = "SERVER_NOT_FOUND";
        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
        goto errout;
    } else if (errcode) {
        state->status = "LOOKING_UP_SERVER";
        goto errout;
    }

    if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) {
        state->status = "TIMEOFDAY";
        goto errout;
    }
    state->authtime = state->kdc_time; /* for audit_as_request() */

    if ((errcode = validate_as_request(kdc_active_realm,
                                       state->request, *state->client,
                                       *state->server, state->kdc_time,
                                       &state->status, &state->e_data))) {
        if (!state->status)
            state->status = "UNKNOWN_REASON";
        errcode += ERROR_TABLE_BASE_krb5;
        goto errout;
    }

    /*
     * Select the keytype for the ticket session key.
     */
    if ((useenctype = select_session_keytype(kdc_active_realm, state->server,
                                             state->request->nktypes,
                                             state->request->ktype)) == 0) {
        /* unsupported ktype */
        state->status = "BAD_ENCRYPTION_TYPE";
        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
        goto errout;
    }

    if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
                                          &state->session_key))) {
        state->status = "RANDOM_KEY_FAILED";
        goto errout;
    }

    /*
     * Canonicalization is only effective if we are issuing a TGT
     * (the intention is to allow support for Windows "short" realm
     * aliases, nothing more).
     */
    if (isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE) &&
        krb5_is_tgs_principal(state->request->server) &&
        krb5_is_tgs_principal(state->server->princ)) {
        state->ticket_reply.server = state->server->princ;
    } else {
        state->ticket_reply.server = state->request->server;
    }

    state->enc_tkt_reply.flags = 0;
    state->enc_tkt_reply.times.authtime = state->authtime;

    setflag(state->enc_tkt_reply.flags, TKT_FLG_INITIAL);
    setflag(state->enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);

    /*
     * It should be noted that local policy may affect the
     * processing of any of these flags.  For example, some
     * realms may refuse to issue renewable tickets
     */

    if (isflagset(state->request->kdc_options, KDC_OPT_FORWARDABLE))
        setflag(state->enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);

    if (isflagset(state->request->kdc_options, KDC_OPT_PROXIABLE))
        setflag(state->enc_tkt_reply.flags, TKT_FLG_PROXIABLE);

    if (isflagset(state->request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
        setflag(state->enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);

    state->enc_tkt_reply.session = &state->session_key;
    if (isflagset(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
        state->client_princ = *(state->client->princ);
    } else {
        state->client_princ = *(state->request->client);
        /* The realm is always canonicalized */
        state->client_princ.realm = state->client->princ->realm;
    }
    state->enc_tkt_reply.client = &state->client_princ;
    state->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
    state->enc_tkt_reply.transited.tr_contents = empty_string;

    if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED)) {
        setflag(state->enc_tkt_reply.flags, TKT_FLG_POSTDATED);
        setflag(state->enc_tkt_reply.flags, TKT_FLG_INVALID);
        state->enc_tkt_reply.times.starttime = state->request->from;
    } else
        state->enc_tkt_reply.times.starttime = state->kdc_time;

    kdc_get_ticket_endtime(kdc_active_realm,
                           state->enc_tkt_reply.times.starttime,
                           kdc_infinity, state->request->till, state->client,
                           state->server, &state->enc_tkt_reply.times.endtime);

    if (isflagset(state->request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
        !isflagset(state->client->attributes, KRB5_KDB_DISALLOW_RENEWABLE) &&
        (state->enc_tkt_reply.times.endtime < state->request->till)) {

        /* we set the RENEWABLE option for later processing */

        setflag(state->request->kdc_options, KDC_OPT_RENEWABLE);
        state->request->rtime = state->request->till;
    }
    rtime = (state->request->rtime == 0) ? kdc_infinity :
        state->request->rtime;

    if (isflagset(state->request->kdc_options, KDC_OPT_RENEWABLE)) {
        /*
         * XXX Should we squelch the output renew_till to be no
         * earlier than the endtime of the ticket?
         */
        setflag(state->enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
        state->enc_tkt_reply.times.renew_till =
            min(rtime, state->enc_tkt_reply.times.starttime +
                min(state->client->max_renewable_life,
                    min(state->server->max_renewable_life,
                        max_renewable_life_for_realm)));
    } else
        state->enc_tkt_reply.times.renew_till = 0; /* XXX */

    /*
     * starttime is optional, and treated as authtime if not present.
     * so we can nuke it if it matches
     */
    if (state->enc_tkt_reply.times.starttime ==
        state->enc_tkt_reply.times.authtime)
        state->enc_tkt_reply.times.starttime = 0;

    state->enc_tkt_reply.caddrs = state->request->addresses;
    state->enc_tkt_reply.authorization_data = 0;

    /* If anonymous requests are being used, adjust the realm of the client
     * principal. */
    if (isflagset(state->request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
        if (!krb5_principal_compare_any_realm(kdc_context,
                                              state->request->client,
                                              krb5_anonymous_principal())) {
            errcode = KRB5KDC_ERR_BADOPTION;
            state->status = "Anonymous requested but anonymous "
                "principal not used.";
            goto errout;
        }
        setflag(state->enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
        krb5_free_principal(kdc_context, state->request->client);
        state->request->client = NULL;
        errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
                                      &state->request->client);
        if (errcode) {
            state->status = "Copying anonymous principal";
            goto errout;
        }
        state->enc_tkt_reply.client = state->request->client;
        setflag(state->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH);
    }

    /*
     * Check the preauthentication if it is there.
     */
    if (state->request->padata) {
        check_padata(kdc_context, &state->rock, state->req_pkt,
                     state->request, &state->enc_tkt_reply, &state->pa_context,
                     &state->e_data, &state->typed_e_data, finish_preauth,
                     state);
    } else
        finish_preauth(state, 0);
    return;

errout:
    finish_process_as_req(state, errcode);
}
Ejemplo n.º 9
0
/*
 * Initialize a realm control structure from the alternate profile or from
 * the specified defaults.
 *
 * After we're complete here, the essence of the realm is embodied in the
 * realm data and we should be all set to begin operation for that realm.
 */
static krb5_error_code
init_realm(krb5_context kcontext, char *progname, kdc_realm_t *rdp, char *realm,
	   char *def_mpname, krb5_enctype def_enctype, char *def_udp_ports,
	   char *def_tcp_ports, krb5_boolean def_manual, char **db_args)
{
    krb5_error_code	kret;
    krb5_boolean	manual;
    krb5_realm_params	*rparams;

    memset((char *) rdp, 0, sizeof(kdc_realm_t));
    if (!realm) {
	kret = EINVAL;
	goto whoops;
    }
	
    rdp->realm_name = realm;
    kret = krb5int_init_context_kdc(&rdp->realm_context);
    if (kret) {
	com_err(progname, kret, gettext("while getting context for realm %s"),
		realm);
	goto whoops;
    }

    /*
     * Solaris Kerberos:
     * Set the current context to that of the realm being init'ed
     */
    krb5_klog_set_context(rdp->realm_context);

    kret = krb5_read_realm_params(rdp->realm_context, rdp->realm_name,
				  &rparams);
    if (kret) {
	com_err(progname, kret, gettext("while reading realm parameters"));
	goto whoops;
    }
    
    /* Handle profile file name */
    if (rparams && rparams->realm_profile)
	rdp->realm_profile = strdup(rparams->realm_profile);

    /* Handle master key name */
    if (rparams && rparams->realm_mkey_name)
	rdp->realm_mpname = strdup(rparams->realm_mkey_name);
    else
	rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) :
	    strdup(KRB5_KDB_M_NAME);

    /* Handle KDC ports */
    if (rparams && rparams->realm_kdc_ports)
	rdp->realm_ports = strdup(rparams->realm_kdc_ports);
    else
	rdp->realm_ports = strdup(def_udp_ports);
    if (rparams && rparams->realm_kdc_tcp_ports)
	rdp->realm_tcp_ports = strdup(rparams->realm_kdc_tcp_ports);
    else
	rdp->realm_tcp_ports = strdup(def_tcp_ports);

    /* Handle stash file */
    if (rparams && rparams->realm_stash_file) {
	rdp->realm_stash = strdup(rparams->realm_stash_file);
	manual = FALSE;
    } else
	manual = def_manual;

    /* Handle master key type */
    if (rparams && rparams->realm_enctype_valid)
	rdp->realm_mkey.enctype = (krb5_enctype) rparams->realm_enctype;
    else
	rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN;

    /* Handle reject-bad-transit flag */
    if (rparams && rparams->realm_reject_bad_transit_valid)
	rdp->realm_reject_bad_transit = rparams->realm_reject_bad_transit;
    else
	rdp->realm_reject_bad_transit = 1;

    /* Handle ticket maximum life */
    rdp->realm_maxlife = (rparams && rparams->realm_max_life_valid) ?
	rparams->realm_max_life : KRB5_KDB_MAX_LIFE;

    /* Handle ticket renewable maximum life */
    rdp->realm_maxrlife = (rparams && rparams->realm_max_rlife_valid) ?
	rparams->realm_max_rlife : KRB5_KDB_MAX_RLIFE;

    if (rparams)
	krb5_free_realm_params(rdp->realm_context, rparams);

    /*
     * We've got our parameters, now go and setup our realm context.
     */

    /* Set the default realm of this context */
    if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) {
	com_err(progname, kret, gettext("while setting default realm to %s"),
		realm);
	goto whoops;
    }

    /* first open the database  before doing anything */
#ifdef KRBCONF_KDC_MODIFIES_KDB    
    if ((kret = krb5_db_open(rdp->realm_context, db_args, 
			     KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_KDC))) {
#else
    if ((kret = krb5_db_open(rdp->realm_context, db_args, 
			     KRB5_KDB_OPEN_RO | KRB5_KDB_SRV_TYPE_KDC))) {
#endif
	/*
	 * Solaris Kerberos:
	 * Make sure that error messages are printed using gettext
	 */
	com_err(progname, kret,
	    gettext("while initializing database for realm %s"), realm);
	goto whoops;
    }

    /* Assemble and parse the master key name */
    if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname,
					rdp->realm_name, (char **) NULL,
					&rdp->realm_mprinc))) {
	com_err(progname, kret,
		gettext("while setting up master key name %s for realm %s"),
		rdp->realm_mpname, realm);
	goto whoops;
    }

    /*
     * Get the master key.
     */
    if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
				   rdp->realm_mkey.enctype, manual,
				   FALSE, rdp->realm_stash,
				   0, &rdp->realm_mkey))) {
	com_err(progname, kret,
		gettext("while fetching master key %s for realm %s"),
		rdp->realm_mpname, realm);
	goto whoops;
    }

    /* Verify the master key */
    if ((kret = krb5_db_verify_master_key(rdp->realm_context,
					  rdp->realm_mprinc,
					  &rdp->realm_mkey))) {
	com_err(progname, kret,
		gettext("while verifying master key for realm %s"),
		realm);
	goto whoops;
    }

    if ((kret = krb5_db_set_mkey(rdp->realm_context, &rdp->realm_mkey))) {
	com_err(progname, kret,
		gettext("while processing master key for realm %s"),
		realm);
	goto whoops;
    }

    /* Set up the keytab */
    if ((kret = krb5_ktkdb_resolve(rdp->realm_context, NULL,
				   &rdp->realm_keytab))) {
	com_err(progname, kret,
		gettext("while resolving kdb keytab for realm %s"),
		realm);
	goto whoops;
    }

    /* Preformat the TGS name */
    if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc,
				     strlen(realm), realm, KRB5_TGS_NAME,
				     realm, (char *) NULL))) {
	com_err(progname, kret,
		gettext("while building TGS name for realm %s"),
		realm);
	goto whoops;
    }

    if (!rkey_init_done) {
	krb5_data seed;
#ifdef KRB5_KRB4_COMPAT
	krb5_keyblock temp_key;
#endif
	/*
	 * If all that worked, then initialize the random key
	 * generators.
	 */

	seed.length = rdp->realm_mkey.length;
	seed.data = (char *)rdp->realm_mkey.contents;
/* SUNW14resync - XXX */
#if 0
	if ((kret = krb5_c_random_add_entropy(rdp->realm_context,
					     KRB5_C_RANDSOURCE_TRUSTEDPARTY, &seed)))
	    goto whoops;
#endif

#ifdef KRB5_KRB4_COMPAT
	if ((kret = krb5_c_make_random_key(rdp->realm_context,
					   ENCTYPE_DES_CBC_CRC, &temp_key))) {
	    com_err(progname, kret,
		    "while initializing V4 random key generator");
	    goto whoops;
	}

	(void) des_init_random_number_generator(temp_key.contents);
	krb5_free_keyblock_contents(rdp->realm_context, &temp_key);
#endif
	rkey_init_done = 1;
    }
 whoops:
    /*
     * If we choked, then clean up any dirt we may have dropped on the floor.
     */
    if (kret) {
        
	finish_realm(rdp);
    }

    /*
     * Solaris Kerberos:
     * Set the current context back to the general context
     */
    krb5_klog_set_context(kcontext);

    return(kret);
}

krb5_sigtype
request_exit(int signo)
{
    signal_requests_exit = 1;

#ifdef POSIX_SIGTYPE
    return;
#else
    return(0);
#endif
}
Ejemplo n.º 10
0
krb5_error_code
kdc_fast_response_handle_padata(struct kdc_request_state *state,
                                krb5_kdc_req *request,
                                krb5_kdc_rep *rep, krb5_enctype enctype)
{
    krb5_error_code retval = 0;
    krb5_fast_finished finish;
    krb5_fast_response fast_response;
    krb5_data *encoded_ticket = NULL;
    krb5_data *encrypted_reply = NULL;
    krb5_pa_data *pa = NULL, **pa_array = NULL;
    krb5_cksumtype cksumtype = CKSUMTYPE_RSA_MD5;
    krb5_pa_data *empty_padata[] = {NULL};
    krb5_keyblock *strengthen_key = NULL;
    kdc_realm_t *kdc_active_realm = state->realm_data;

    if (!state->armor_key)
        return 0;
    memset(&finish, 0, sizeof(finish));
    retval = krb5_init_keyblock(kdc_context, enctype, 0, &strengthen_key);
    if (retval == 0)
        retval = krb5_c_make_random_key(kdc_context, enctype, strengthen_key);
    if (retval == 0) {
        state->strengthen_key = strengthen_key;
        strengthen_key = NULL;
    }

    fast_response.padata = rep->padata;
    if (fast_response.padata == NULL)
        fast_response.padata = &empty_padata[0];
    fast_response.strengthen_key = state->strengthen_key;
    fast_response.nonce = request->nonce;
    fast_response.finished = &finish;
    finish.client = rep->client;
    pa_array = calloc(3, sizeof(*pa_array));
    if (pa_array == NULL)
        retval = ENOMEM;
    pa = calloc(1, sizeof(krb5_pa_data));
    if (retval == 0 && pa == NULL)
        retval = ENOMEM;
    if (retval == 0)
        retval = krb5_us_timeofday(kdc_context, &finish.timestamp, &finish.usec);
    if (retval == 0)
        retval = encode_krb5_ticket(rep->ticket, &encoded_ticket);
    if (retval == 0)
        retval = krb5int_c_mandatory_cksumtype(kdc_context,
                                               state->armor_key->enctype,
                                               &cksumtype);
    if (retval == 0)
        retval = krb5_c_make_checksum(kdc_context, cksumtype,
                                      state->armor_key,
                                      KRB5_KEYUSAGE_FAST_FINISHED,
                                      encoded_ticket, &finish.ticket_checksum);
    if (retval == 0)
        retval = encrypt_fast_reply(state, &fast_response, &encrypted_reply);
    if (retval == 0) {
        pa[0].pa_type = KRB5_PADATA_FX_FAST;
        pa[0].length = encrypted_reply->length;
        pa[0].contents = (unsigned char *)  encrypted_reply->data;
        pa_array[0] = &pa[0];
        krb5_free_pa_data(kdc_context, rep->padata);
        rep->padata = pa_array;
        pa_array = NULL;
        free(encrypted_reply);
        encrypted_reply = NULL;
        pa = NULL;
    }
    if (pa)
        free(pa);
    if (pa_array)
        free(pa_array);
    if (encrypted_reply)
        krb5_free_data(kdc_context, encrypted_reply);
    if (encoded_ticket)
        krb5_free_data(kdc_context, encoded_ticket);
    if (strengthen_key != NULL)
        krb5_free_keyblock(kdc_context, strengthen_key);
    if (finish.ticket_checksum.contents)
        krb5_free_checksum_contents(kdc_context, &finish.ticket_checksum);
    return retval;
}
Ejemplo n.º 11
0
/* Create the response for a client. */
static krb5_error_code
server_return(krb5_context kcontext,
	      krb5_pa_data *padata,
	      struct _krb5_db_entry_new *client,
	      krb5_data *req_pkt,
	      krb5_kdc_req *request,
	      krb5_kdc_rep *reply,
	      struct _krb5_key_data *client_key,
	      krb5_keyblock *encrypting_key,
	      krb5_pa_data **send_pa,
	      preauth_get_entry_data_proc server_get_entry_data,
	      void *pa_module_context,
	      void **pa_request_context)
{
    /* This module does a couple of dumb things.  It tags its reply with
     * the same type as the initial challenge (expecting the client to sort
     * out whether there's anything useful in there).  Oh, and it replaces
     * the AS reply key with one which is sent in the clear. */
    krb5_keyblock *kb;
    krb5_int32 enctype;
    int i;

    *send_pa = NULL;

    /* We'll want a key with the first supported enctype. */
    for (i = 0; i < request->nktypes; i++) {
	kb = NULL;
	if (krb5_init_keyblock(kcontext, request->ktype[i], 0, &kb) == 0) {
	    break;
	}
    }
    if (i >= request->nktypes) {
	/* No matching cipher type found. */
	return 0;
    }

    /* Randomize a key and save it for the client. */
    if (krb5_c_make_random_key(kcontext, request->ktype[i], kb) != 0) {
	krb5_free_keyblock(kcontext, kb);
	return 0;
    }
#ifdef DEBUG
    fprintf(stderr, "Generated random key, type=%d, length=%d.\n",
	    kb->enctype, kb->length);
#endif

    *send_pa = malloc(sizeof(krb5_pa_data));
    if (*send_pa == NULL) {
	krb5_free_keyblock(kcontext, kb);
	return ENOMEM;
    }
    (*send_pa)->pa_type = KRB5_PADATA_WPSE_REQ;
    (*send_pa)->length = 4 + kb->length;
    (*send_pa)->contents = malloc(4 + kb->length);
    if ((*send_pa)->contents == NULL) {
	free(*send_pa);
	*send_pa = NULL;
	krb5_free_keyblock(kcontext, kb);
	return ENOMEM;
    }

    /* Store the preauth data. */
    enctype = htonl(kb->enctype);
    memcpy((*send_pa)->contents, &enctype, 4);
    memcpy((*send_pa)->contents + 4, kb->contents, kb->length);
    krb5_free_keyblock_contents(kcontext, encrypting_key);
    krb5_copy_keyblock_contents(kcontext, kb, encrypting_key);

    /* Clean up. */
    krb5_free_keyblock(kcontext, kb);

    return 0;
}
Ejemplo n.º 12
0
int
main ()
{
    krb5_context context = 0;
    krb5_data  in, in2, out, out2, check, check2, state, signdata;
    krb5_crypto_iov iov[5];
    int i, j, pos;
    unsigned int dummy;
    size_t len;
    krb5_enc_data enc_out, enc_out2;
    krb5_keyblock *keyblock;
    krb5_key key;

    memset(iov, 0, sizeof(iov));

    in.data = "This is a test.\n";
    in.length = strlen (in.data);
    in2.data = "This is another test.\n";
    in2.length = strlen (in2.data);

    test ("Seeding random number generator",
          krb5_c_random_seed (context, &in));

    /* Set up output buffers. */
    out.data = malloc(2048);
    out2.data = malloc(2048);
    check.data = malloc(2048);
    check2.data = malloc(2048);
    if (out.data == NULL || out2.data == NULL
        || check.data == NULL || check2.data == NULL)
        abort();
    out.magic = KV5M_DATA;
    out.length = 2048;
    out2.magic = KV5M_DATA;
    out2.length = 2048;
    check.length = 2048;
    check2.length = 2048;

    for (i = 0; interesting_enctypes[i]; i++) {
        krb5_enctype enctype = interesting_enctypes [i];

        printf ("Testing enctype %d\n", enctype);
        test ("Initializing a keyblock",
              krb5_init_keyblock (context, enctype, 0, &keyblock));
        test ("Generating random keyblock",
              krb5_c_make_random_key (context, enctype, keyblock));
        test ("Creating opaque key from keyblock",
              krb5_k_create_key (context, keyblock, &key));

        enc_out.ciphertext = out;
        enc_out2.ciphertext = out2;
        /* We use an intermediate `len' because size_t may be different size
           than `int' */
        krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len);
        enc_out.ciphertext.length = len;

        /* Encrypt, decrypt, and see if we got the plaintext back again. */
        test ("Encrypting (c)",
              krb5_c_encrypt (context, keyblock, 7, 0, &in, &enc_out));
        display ("Enc output", &enc_out.ciphertext);
        test ("Decrypting",
              krb5_c_decrypt (context, keyblock, 7, 0, &enc_out, &check));
        test ("Comparing", compare_results (&in, &check));

        /* Try again with the opaque-key-using variants. */
        memset(out.data, 0, out.length);
        test ("Encrypting (k)",
              krb5_k_encrypt (context, key, 7, 0, &in, &enc_out));
        display ("Enc output", &enc_out.ciphertext);
        test ("Decrypting",
              krb5_k_decrypt (context, key, 7, 0, &enc_out, &check));
        test ("Comparing", compare_results (&in, &check));

        /* Check if this enctype supports IOV encryption. */
        if ( krb5_c_crypto_length(context, keyblock->enctype,
                                  KRB5_CRYPTO_TYPE_HEADER, &dummy) == 0 ){
            /* Set up iovecs for stream decryption. */
            memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length);
            iov[0].flags= KRB5_CRYPTO_TYPE_STREAM;
            iov[0].data.data = out2.data;
            iov[0].data.length = enc_out.ciphertext.length;
            iov[1].flags = KRB5_CRYPTO_TYPE_DATA;

            /* Decrypt the encrypted data from above and check it. */
            test("IOV stream decrypting (c)",
                 krb5_c_decrypt_iov( context, keyblock, 7, 0, iov, 2));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));

            /* Try again with the opaque-key-using variant. */
            memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length);
            test("IOV stream decrypting (k)",
                 krb5_k_decrypt_iov( context, key, 7, 0, iov, 2));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));

            /* Set up iovecs for AEAD encryption. */
            signdata.magic = KV5M_DATA;
            signdata.data = (char *) "This should be signed";
            signdata.length = strlen(signdata.data);
            iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
            iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
            iov[1].data = in; /*We'll need to copy memory before encrypt*/
            iov[2].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
            iov[2].data = signdata;
            iov[3].flags = KRB5_CRYPTO_TYPE_PADDING;
            iov[4].flags = KRB5_CRYPTO_TYPE_TRAILER;

            /* "Allocate" data for the iovec buffers from the "out" buffer. */
            test("Setting up iov lengths",
                 krb5_c_crypto_length_iov(context, keyblock->enctype, iov, 5));
            for (j=0,pos=0; j <= 4; j++ ){
                if (iov[j].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
                    continue;
                iov[j].data.data = &out.data[pos];
                pos += iov[j].data.length;
            }
            assert (iov[1].data.length == in.length);
            memcpy(iov[1].data.data, in.data, in.length);

            /* Encrypt and decrypt in place, and check the result. */
            test("iov encrypting (c)",
                 krb5_c_encrypt_iov(context, keyblock, 7, 0, iov, 5));
            assert(iov[1].data.length == in.length);
            display("Header", &iov[0].data);
            display("Data", &iov[1].data);
            display("Padding", &iov[3].data);
            display("Trailer", &iov[4].data);
            test("iov decrypting",
                 krb5_c_decrypt_iov(context, keyblock, 7, 0, iov, 5));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));

            /* Try again with opaque-key-using variants. */
            test("iov encrypting (k)",
                 krb5_k_encrypt_iov(context, key, 7, 0, iov, 5));
            assert(iov[1].data.length == in.length);
            display("Header", &iov[0].data);
            display("Data", &iov[1].data);
            display("Padding", &iov[3].data);
            display("Trailer", &iov[4].data);
            test("iov decrypting",
                 krb5_k_decrypt_iov(context, key, 7, 0, iov, 5));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));
        }

        enc_out.ciphertext.length = out.length;
        check.length = 2048;

        test ("init_state",
              krb5_c_init_state (context, keyblock, 7, &state));
        test ("Encrypting with state",
              krb5_c_encrypt (context, keyblock, 7, &state, &in, &enc_out));
        display ("Enc output", &enc_out.ciphertext);
        test ("Encrypting again with state",
              krb5_c_encrypt (context, keyblock, 7, &state, &in2, &enc_out2));
        display ("Enc output", &enc_out2.ciphertext);
        test ("free_state",
              krb5_c_free_state (context, keyblock, &state));
        test ("init_state",
              krb5_c_init_state (context, keyblock, 7, &state));
        test ("Decrypting with state",
              krb5_c_decrypt (context, keyblock, 7, &state, &enc_out, &check));
        test ("Decrypting again with state",
              krb5_c_decrypt (context, keyblock, 7, &state, &enc_out2, &check2));
        test ("free_state",
              krb5_c_free_state (context, keyblock, &state));
        test ("Comparing",
              compare_results (&in, &check));
        test ("Comparing",
              compare_results (&in2, &check2));

        krb5_free_keyblock (context, keyblock);
        krb5_k_free_key (context, key);
    }

    /* Test the RC4 decrypt fallback from key usage 9 to 8. */
    test ("Initializing an RC4 keyblock",
          krb5_init_keyblock (context, ENCTYPE_ARCFOUR_HMAC, 0, &keyblock));
    test ("Generating random RC4 key",
          krb5_c_make_random_key (context, ENCTYPE_ARCFOUR_HMAC, keyblock));
    enc_out.ciphertext = out;
    krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len);
    enc_out.ciphertext.length = len;
    check.length = 2048;
    test ("Encrypting with RC4 key usage 8",
          krb5_c_encrypt (context, keyblock, 8, 0, &in, &enc_out));
    display ("Enc output", &enc_out.ciphertext);
    test ("Decrypting with RC4 key usage 9",
          krb5_c_decrypt (context, keyblock, 9, 0, &enc_out, &check));
    test ("Comparing", compare_results (&in, &check));

    krb5_free_keyblock (context, keyblock);
    free(out.data);
    free(out2.data);
    free(check.data);
    free(check2.data);
    return 0;
}
Ejemplo n.º 13
0
static krb5_error_code
setup_sam(void)
{
    krb5_context ctx = shandle.kdc_err_context;
    return krb5_c_make_random_key(ctx, ENCTYPE_DES_CBC_MD5, &psr_key);
}
/*ARGSUSED*/
krb5_error_code
process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
		krb5_data **response)
{
    krb5_keyblock * subkey = 0;
    krb5_kdc_req *request = 0;
    krb5_db_entry server;
    krb5_kdc_rep reply;
    krb5_enc_kdc_rep_part reply_encpart;
    krb5_ticket ticket_reply, *header_ticket = 0;
    int st_idx = 0;
    krb5_enc_tkt_part enc_tkt_reply;
    krb5_transited enc_tkt_transited;
    int newtransited = 0;
    krb5_error_code retval = 0;
    int nprincs = 0;
    krb5_boolean more;
    krb5_timestamp kdc_time, authtime=0;
    krb5_keyblock session_key;
    krb5_timestamp until, rtime;
    krb5_keyblock encrypting_key;
    krb5_key_data  *server_key;
    char *cname = 0, *sname = 0, *tmp = 0;
    const char *fromstring = 0;
    krb5_last_req_entry *nolrarray[2], nolrentry;
/*    krb5_address *noaddrarray[1]; */
    krb5_enctype useenctype;
    int	errcode, errcode2;
    register int i;
    int firstpass = 1;
    const char	*status = 0;
    char ktypestr[128];
    char rep_etypestr[128];
    char fromstringbuf[70];

    session_key.contents = 0;
    
    retval = decode_krb5_tgs_req(pkt, &request);
    if (retval)
	return retval;
    if (request->msg_type != KRB5_TGS_REQ)
        return KRB5_BADMSGTYPE;

    ktypes2str(ktypestr, sizeof(ktypestr),
	       request->nktypes, request->ktype);
    /*
     * setup_server_realm() sets up the global realm-specific data pointer.
     */
    if ((retval = setup_server_realm(request->server))) {
	krb5_free_kdc_req(kdc_context, request);
	return retval;
    }

    fromstring = inet_ntop(ADDRTYPE2FAMILY(from->address->addrtype),
			   from->address->contents,
			   fromstringbuf, sizeof(fromstringbuf));
    if (!fromstring)
	fromstring = "<unknown>";

    if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
	status = "UNPARSING SERVER";
	goto cleanup;
    }
    limit_string(sname);

   /* errcode = kdc_process_tgs_req(request, from, pkt, &req_authdat); */
    errcode = kdc_process_tgs_req(request, from, pkt, &header_ticket, &subkey);

    if (header_ticket && header_ticket->enc_part2 &&
	(errcode2 = krb5_unparse_name(kdc_context, 
				      header_ticket->enc_part2->client,
				      &cname))) {
	status = "UNPARSING CLIENT";
	errcode = errcode2;
	goto cleanup;
    }
    limit_string(cname);
    
    if (errcode) {
	status = "PROCESS_TGS";
	goto cleanup;
    }

    if (!header_ticket) {
	errcode = KRB5_NO_TKT_SUPPLIED;	/* XXX? */
	status="UNEXPECTED NULL in header_ticket";
	goto cleanup;
    }
    
    /*
     * We've already dealt with the AP_REQ authentication, so we can
     * use header_ticket freely.  The encrypted part (if any) has been
     * decrypted with the session key.
     */

    authtime = header_ticket->enc_part2->times.authtime;

    /* XXX make sure server here has the proper realm...taken from AP_REQ
       header? */

    nprincs = 1;
    if ((errcode = get_principal(kdc_context, request->server, &server,
				 &nprincs, &more))) {
	status = "LOOKING_UP_SERVER";
	nprincs = 0;
	goto cleanup;
    }
tgt_again:
    if (more) {
	status = "NON_UNIQUE_PRINCIPAL";
	errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
	goto cleanup;
    } else if (nprincs != 1) {
	/*
	 * might be a request for a TGT for some other realm; we
	 * should do our best to find such a TGS in this db
	 */
	if (firstpass && krb5_is_tgs_principal(request->server) == TRUE) {
	    if (krb5_princ_size(kdc_context, request->server) == 2) {
		krb5_data *server_1 =
		    krb5_princ_component(kdc_context, request->server, 1);
		krb5_data *tgs_1 =
		    krb5_princ_component(kdc_context, tgs_server, 1);

		if (!tgs_1 || !data_eq(*server_1, *tgs_1)) {
		    krb5_db_free_principal(kdc_context, &server, nprincs);
		    find_alternate_tgs(request, &server, &more, &nprincs);
		    firstpass = 0;
		    goto tgt_again;
		}
	    }
	}
	krb5_db_free_principal(kdc_context, &server, nprincs);
	status = "UNKNOWN_SERVER";
	errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
	goto cleanup;
    }

    if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) {
	status = "TIME_OF_DAY";
	goto cleanup;
    }
    
    if ((retval = validate_tgs_request(request, server, header_ticket,
				      kdc_time, &status))) {
	if (!status)
	    status = "UNKNOWN_REASON";
	errcode = retval + ERROR_TABLE_BASE_krb5;
	goto cleanup;
    }

    /*
     * We pick the session keytype here....
     * 
     * Some special care needs to be taken in the user-to-user
     * case, since we don't know what keytypes the application server
     * which is doing user-to-user authentication can support.  We
     * know that it at least must be able to support the encryption
     * type of the session key in the TGT, since otherwise it won't be
     * able to decrypt the U2U ticket!  So we use that in preference
     * to anything else.
     */
    useenctype = 0;
    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
	krb5_keyblock *	st_sealing_key;
	krb5_kvno 	st_srv_kvno;
	krb5_enctype	etype;

	/*
	 * Get the key for the second ticket, and decrypt it.
	 */
	if ((errcode = kdc_get_server_key(request->second_ticket[st_idx],
					 &st_sealing_key,
					 &st_srv_kvno))) {
	    status = "2ND_TKT_SERVER";
	    goto cleanup;
	}
	errcode = krb5_decrypt_tkt_part(kdc_context, st_sealing_key,
				       request->second_ticket[st_idx]);
	krb5_free_keyblock(kdc_context, st_sealing_key);
	if (errcode) {
	    status = "2ND_TKT_DECRYPT";
	    goto cleanup;
	}
	
	etype = request->second_ticket[st_idx]->enc_part2->session->enctype;
	if (!krb5_c_valid_enctype(etype)) {
	    status = "BAD_ETYPE_IN_2ND_TKT";
	    errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
	    goto cleanup;
	}
	
	for (i = 0; i < request->nktypes; i++) {
	    if (request->ktype[i] == etype) {
		useenctype = etype;
		break;
	    }
	}
    }

    /*
     * Select the keytype for the ticket session key.
     */
    if ((useenctype == 0) &&
	(useenctype = select_session_keytype(kdc_context, &server,
					     request->nktypes,
					     request->ktype)) == 0) {
	/* unsupported ktype */
	status = "BAD_ENCRYPTION_TYPE";
	errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
	goto cleanup;
    }
    
    errcode = krb5_c_make_random_key(kdc_context, useenctype, &session_key);

    if (errcode) {
	/* random key failed */
	status = "RANDOM_KEY_FAILED";
	goto cleanup;
    }

    ticket_reply.server = request->server; /* XXX careful for realm... */

    enc_tkt_reply.flags = 0;
    enc_tkt_reply.times.starttime = 0;

    /*
     * Fix header_ticket's starttime; if it's zero, fill in the
     * authtime's value.
     */
    if (!(header_ticket->enc_part2->times.starttime))
	header_ticket->enc_part2->times.starttime =
	    header_ticket->enc_part2->times.authtime;

    /* don't use new addresses unless forwarded, see below */

    enc_tkt_reply.caddrs = header_ticket->enc_part2->caddrs;
    /* noaddrarray[0] = 0; */
    reply_encpart.caddrs = 0;		/* optional...don't put it in */

    /* It should be noted that local policy may affect the  */
    /* processing of any of these flags.  For example, some */
    /* realms may refuse to issue renewable tickets         */

    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE))
	setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);

    if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) {
	setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);

	/* include new addresses in ticket & reply */

	enc_tkt_reply.caddrs = request->addresses;
	reply_encpart.caddrs = request->addresses;
    }	
    if (isflagset(header_ticket->enc_part2->flags, TKT_FLG_FORWARDED))
	setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);

    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE))
	setflag(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);

    if (isflagset(request->kdc_options, KDC_OPT_PROXY)) {
	setflag(enc_tkt_reply.flags, TKT_FLG_PROXY);

	/* include new addresses in ticket & reply */

	enc_tkt_reply.caddrs = request->addresses;
	reply_encpart.caddrs = request->addresses;
    }

    if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
	setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);

    if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
	setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
	setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
	enc_tkt_reply.times.starttime = request->from;
    } else
	enc_tkt_reply.times.starttime = kdc_time;

    if (isflagset(request->kdc_options, KDC_OPT_VALIDATE)) {
	/* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
	   to the caller */
	ticket_reply = *(header_ticket);
	enc_tkt_reply = *(header_ticket->enc_part2);
        enc_tkt_reply.authorization_data = NULL;
	clear(enc_tkt_reply.flags, TKT_FLG_INVALID);
    }

    if (isflagset(request->kdc_options, KDC_OPT_RENEW)) {
	krb5_deltat old_life;

	/* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
	   to the caller */
	ticket_reply = *(header_ticket);
	enc_tkt_reply = *(header_ticket->enc_part2);
        enc_tkt_reply.authorization_data = NULL;

	old_life = enc_tkt_reply.times.endtime - enc_tkt_reply.times.starttime;

	enc_tkt_reply.times.starttime = kdc_time;
	enc_tkt_reply.times.endtime =
	    min(header_ticket->enc_part2->times.renew_till,
		kdc_time + old_life);
    } else {
	/* not a renew request */
	enc_tkt_reply.times.starttime = kdc_time;
	until = (request->till == 0) ? kdc_infinity : request->till;
	enc_tkt_reply.times.endtime =
	    min(until, min(enc_tkt_reply.times.starttime + server.max_life,
			   min(enc_tkt_reply.times.starttime + max_life_for_realm,
			       header_ticket->enc_part2->times.endtime)));
	if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
	    (enc_tkt_reply.times.endtime < request->till) &&
	    isflagset(header_ticket->enc_part2->flags,
		  TKT_FLG_RENEWABLE)) {
	    setflag(request->kdc_options, KDC_OPT_RENEWABLE);
	    request->rtime =
		min(request->till,
		    header_ticket->enc_part2->times.renew_till);
	}
    }
    rtime = (request->rtime == 0) ? kdc_infinity : request->rtime;

    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) {
	/* already checked above in policy check to reject request for a
	   renewable ticket using a non-renewable ticket */
	setflag(enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
	enc_tkt_reply.times.renew_till =
	    min(rtime,
		min(header_ticket->enc_part2->times.renew_till,
		    enc_tkt_reply.times.starttime +
		    min(server.max_renewable_life,
			max_renewable_life_for_realm)));
    } else {
	enc_tkt_reply.times.renew_till = 0;
    }
    
    /*
     * Set authtime to be the same as header_ticket's
     */
    enc_tkt_reply.times.authtime = header_ticket->enc_part2->times.authtime;
    
    /*
     * Propagate the preauthentication flags through to the returned ticket.
     */
    if (isflagset(header_ticket->enc_part2->flags, TKT_FLG_PRE_AUTH))
	setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH);

    if (isflagset(header_ticket->enc_part2->flags, TKT_FLG_HW_AUTH))
	setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH);
    
    /* starttime is optional, and treated as authtime if not present.
       so we can nuke it if it matches */
    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
	enc_tkt_reply.times.starttime = 0;

    /* assemble any authorization data */
    if (request->authorization_data.ciphertext.data) {
	krb5_data scratch;

	scratch.length = request->authorization_data.ciphertext.length;
	if (!(scratch.data =
	      malloc(request->authorization_data.ciphertext.length))) {
	    status = "AUTH_NOMEM";
	    errcode = ENOMEM;
	    goto cleanup;
	}

	if ((errcode = krb5_c_decrypt(kdc_context,
				      header_ticket->enc_part2->session,
				      KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
				      0, &request->authorization_data,
				      &scratch))) {
	    status = "AUTH_ENCRYPT_FAIL";
	    free(scratch.data);
	    goto cleanup;
	}

	/* scratch now has the authorization data, so we decode it */
	errcode = decode_krb5_authdata(&scratch, &(request->unenc_authdata));
	free(scratch.data);
	if (errcode) {
	    status = "AUTH_DECODE";
	    goto cleanup;
	}

	if ((errcode =
	     concat_authorization_data(request->unenc_authdata,
				       header_ticket->enc_part2->authorization_data, 
				       &enc_tkt_reply.authorization_data))) {
	    status = "CONCAT_AUTH";
	    goto cleanup;
	}
    } else
	enc_tkt_reply.authorization_data =
	    header_ticket->enc_part2->authorization_data;

    enc_tkt_reply.session = &session_key;
    enc_tkt_reply.client = header_ticket->enc_part2->client;
    enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
    enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */

    /*
     * Only add the realm of the presented tgt to the transited list if 
     * it is different than the local realm (cross-realm) and it is different
     * than the realm of the client (since the realm of the client is already
     * implicitly part of the transited list and should not be explicitly
     * listed).
     */

    /* realm compare is like strcmp, but knows how to deal with these args */
    if (realm_compare(header_ticket->server, tgs_server) ||
	realm_compare(header_ticket->server, enc_tkt_reply.client)) {
	/* tgt issued by local realm or issued by realm of client */
	enc_tkt_reply.transited = header_ticket->enc_part2->transited;
    } else {
	/* tgt issued by some other realm and not the realm of the client */
	/* assemble new transited field into allocated storage */
	if (header_ticket->enc_part2->transited.tr_type !=
	    KRB5_DOMAIN_X500_COMPRESS) {
	    status = "BAD_TRTYPE";
	    errcode = KRB5KDC_ERR_TRTYPE_NOSUPP;
	    goto cleanup;
	}
	enc_tkt_transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
	enc_tkt_transited.magic = 0;
	enc_tkt_transited.tr_contents.magic = 0;
	enc_tkt_transited.tr_contents.data = 0;
	enc_tkt_transited.tr_contents.length = 0;
	enc_tkt_reply.transited = enc_tkt_transited;
	if ((errcode =
	     add_to_transited(&header_ticket->enc_part2->transited.tr_contents,
			      &enc_tkt_reply.transited.tr_contents,
			      header_ticket->server,
			      enc_tkt_reply.client,
			      request->server))) {
	    status = "ADD_TR_FAIL";
	    goto cleanup;
	}
	newtransited = 1;
    }
    if (!isflagset (request->kdc_options, KDC_OPT_DISABLE_TRANSITED_CHECK)) {
	unsigned int tlen;
	char *tdots;

	errcode = krb5_check_transited_list (kdc_context,
					     &enc_tkt_reply.transited.tr_contents,
					     krb5_princ_realm (kdc_context, header_ticket->enc_part2->client),
					     krb5_princ_realm (kdc_context, request->server));
	tlen = enc_tkt_reply.transited.tr_contents.length;
	tdots = tlen > 125 ? "..." : "";
	tlen = tlen > 125 ? 125 : tlen;

	if (errcode == 0) {
	    setflag (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED);
	} else if (errcode == KRB5KRB_AP_ERR_ILL_CR_TKT)
	    krb5_klog_syslog (LOG_INFO,
			      "bad realm transit path from '%s' to '%s' "
			      "via '%.*s%s'",
			      cname ? cname : "<unknown client>",
			      sname ? sname : "<unknown server>",
			      tlen,
			      enc_tkt_reply.transited.tr_contents.data,
			      tdots);
	else {
	    const char *emsg = krb5_get_error_message(kdc_context, errcode);
	    krb5_klog_syslog (LOG_ERR,
			      "unexpected error checking transit from "
			      "'%s' to '%s' via '%.*s%s': %s",
			      cname ? cname : "<unknown client>",
			      sname ? sname : "<unknown server>",
			      tlen,
			      enc_tkt_reply.transited.tr_contents.data,
			      tdots, emsg);
	    krb5_free_error_message(kdc_context, emsg);
	}
    } else
	krb5_klog_syslog (LOG_INFO, "not checking transit path");
    if (reject_bad_transit
	&& !isflagset (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED)) {
	errcode = KRB5KDC_ERR_POLICY;
	status = "BAD_TRANSIT";
	goto cleanup;
    }

    ticket_reply.enc_part2 = &enc_tkt_reply;

    /*
     * If we are doing user-to-user authentication, then make sure
     * that the client for the second ticket matches the request
     * server, and then encrypt the ticket using the session key of
     * the second ticket.
     */
    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
	/*
	 * Make sure the client for the second ticket matches
	 * requested server.
	 */
	krb5_enc_tkt_part *t2enc = request->second_ticket[st_idx]->enc_part2;
	krb5_principal client2 = t2enc->client;
	if (!krb5_principal_compare(kdc_context, request->server, client2)) {
		if ((errcode = krb5_unparse_name(kdc_context, client2, &tmp)))
			tmp = 0;
		if (tmp != NULL)
		    limit_string(tmp);

		krb5_klog_syslog(LOG_INFO,
				 "TGS_REQ %s: 2ND_TKT_MISMATCH: "
				 "authtime %d, %s for %s, 2nd tkt client %s",
				 fromstring, authtime,
				 cname ? cname : "<unknown client>",
				 sname ? sname : "<unknown server>",
				 tmp ? tmp : "<unknown>");
		errcode = KRB5KDC_ERR_SERVER_NOMATCH;
		goto cleanup;
	}
	    
	ticket_reply.enc_part.kvno = 0;
	ticket_reply.enc_part.enctype = t2enc->session->enctype;
	if ((errcode = krb5_encrypt_tkt_part(kdc_context, t2enc->session,
					     &ticket_reply))) {
	    status = "2ND_TKT_ENCRYPT";
	    goto cleanup;
	}
	st_idx++;
    } else {
	/*
	 * Find the server key
	 */
	if ((errcode = krb5_dbe_find_enctype(kdc_context, &server,
					     -1, /* ignore keytype */
					     -1, /* Ignore salttype */
					     0,		/* Get highest kvno */
					     &server_key))) {
	    status = "FINDING_SERVER_KEY";
	    goto cleanup;
	}
	/* convert server.key into a real key (it may be encrypted
	 *        in the database) */
	if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context,
						   &master_keyblock, 
						   server_key, &encrypting_key,
						   NULL))) {
	    status = "DECRYPT_SERVER_KEY";
	    goto cleanup;
	}
	errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key,
					&ticket_reply);
	krb5_free_keyblock_contents(kdc_context, &encrypting_key);
	if (errcode) {
	    status = "TKT_ENCRYPT";
	    goto cleanup;
	}
	ticket_reply.enc_part.kvno = server_key->key_data_kvno;
    }

    /* Start assembling the response */
    reply.msg_type = KRB5_TGS_REP;
    reply.padata = 0;		/* always */
    reply.client = header_ticket->enc_part2->client;
    reply.enc_part.kvno = 0;		/* We are using the session key */
    reply.ticket = &ticket_reply;

    reply_encpart.session = &session_key;
    reply_encpart.nonce = request->nonce;

    /* copy the time fields EXCEPT for authtime; its location
       is used for ktime */
    reply_encpart.times = enc_tkt_reply.times;
    reply_encpart.times.authtime = header_ticket->enc_part2->times.authtime;

    /* starttime is optional, and treated as authtime if not present.
       so we can nuke it if it matches */
    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
	enc_tkt_reply.times.starttime = 0;

    nolrentry.lr_type = KRB5_LRQ_NONE;
    nolrentry.value = 0;
    nolrarray[0] = &nolrentry;
    nolrarray[1] = 0;
    reply_encpart.last_req = nolrarray;	/* not available for TGS reqs */
    reply_encpart.key_exp = 0;		/* ditto */
    reply_encpart.flags = enc_tkt_reply.flags;
    reply_encpart.server = ticket_reply.server;
    
    /* use the session key in the ticket, unless there's a subsession key
       in the AP_REQ */

    reply.enc_part.enctype = subkey ? subkey->enctype :
		    header_ticket->enc_part2->session->enctype;
    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart, 
				  subkey ? 1 : 0,
				  subkey ? subkey :
				  header_ticket->enc_part2->session,
				  &reply, response);
    if (errcode) {
	status = "ENCODE_KDC_REP";
    } else {
	status = "ISSUE";
    }

    memset(ticket_reply.enc_part.ciphertext.data, 0,
	   ticket_reply.enc_part.ciphertext.length);
    free(ticket_reply.enc_part.ciphertext.data);
    /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
       can use them in raw form if needed.  But, we don't... */
    memset(reply.enc_part.ciphertext.data, 0,
	   reply.enc_part.ciphertext.length);
    free(reply.enc_part.ciphertext.data);
    
cleanup:
    if (status) {
	const char * emsg = NULL;
	if (!errcode)
	    rep_etypes2str(rep_etypestr, sizeof(rep_etypestr), &reply);
	if (errcode) 
	    emsg = krb5_get_error_message (kdc_context, errcode);
	krb5_klog_syslog(LOG_INFO,
			 "TGS_REQ (%s) %s: %s: authtime %d, "
			 "%s%s %s for %s%s%s",
			 ktypestr,
			 fromstring, status, authtime,
			 !errcode ? rep_etypestr : "",
			 !errcode ? "," : "",
			 cname ? cname : "<unknown client>",
			 sname ? sname : "<unknown server>",
			 errcode ? ", " : "",
			 errcode ? emsg : "");
	if (errcode)
	    krb5_free_error_message (kdc_context, emsg);
    }
    
    if (errcode) {
        int got_err = 0;
	if (status == 0) {
	    status = krb5_get_error_message (kdc_context, errcode);
	    got_err = 1;
	}
	errcode -= ERROR_TABLE_BASE_krb5;
	if (errcode < 0 || errcode > 128)
	    errcode = KRB_ERR_GENERIC;
	    
	retval = prepare_error_tgs(request, header_ticket, errcode,
				   fromstring, response, status);
	if (got_err) {
	    krb5_free_error_message (kdc_context, status);
	    status = 0;
	}
    }
    
    if (header_ticket)
	krb5_free_ticket(kdc_context, header_ticket);
    if (request)
	krb5_free_kdc_req(kdc_context, request);
    if (cname)
	free(cname);
    if (sname)
	free(sname);
    if (nprincs)
	krb5_db_free_principal(kdc_context, &server, 1);
    if (session_key.contents)
	krb5_free_keyblock_contents(kdc_context, &session_key);
    if (newtransited)
	free(enc_tkt_reply.transited.tr_contents.data);
    if (subkey)
	krb5_free_keyblock(kdc_context, subkey);

    return retval;
}
Ejemplo n.º 15
0
/*
 * Print a krb5 ticket in our service key, for the supplied client principal.
 * The path to a keytab is mandatory, but the service principal may be
 * guessed from the keytab contents if desired.  The keytab entry must be
 * one of the allowed_enctypes (a zero-terminated list) if a non-NULL
 * parameter is passed.
 */
krb5_error_code
get_credv5_akimpersonate(krb5_context context, char* keytab,
			 krb5_principal service_principal,
			 krb5_principal client_principal, time_t starttime,
			 time_t endtime, const int *allowed_enctypes,
			 krb5_creds** out_creds /* out */ )
{
    krb5_error_code code;
    krb5_keytab kt = 0;
    krb5_keytab_entry entry[1];
    krb5_creds *creds = 0;
    krb5_enctype enctype;
    krb5_keyblock session_key[1];
#if USING_HEIMDAL
    Ticket *ticket_reply;
    EncTicketPart *enc_tkt_reply;
#else
    krb5_ticket *ticket_reply;
    krb5_enc_tkt_part *enc_tkt_reply;
#endif
    *out_creds = NULL;
    enctype = 0; /* AKIMPERSONATE_IGNORE_ENCTYPE */
    memset(entry, 0, sizeof *entry);
    memset(session_key, 0, sizeof *session_key);
    ticket_reply = NULL;
    enc_tkt_reply = NULL;

    creds = calloc(1, sizeof(*creds));
    if (creds == NULL) {
        code = ENOMEM;
        goto cleanup;
    }
    code = alloc_ticket(&ticket_reply);
    if (code != 0)
	goto cleanup;
    code = alloc_enc_tkt_part(&enc_tkt_reply);
    if (code != 0)
	goto cleanup;
    /* Empty list of allowed etypes must fail.  Do it here to avoid issues. */
    if (allowed_enctypes != NULL && *allowed_enctypes == 0) {
	code = KRB5_BAD_ENCTYPE;
	goto cleanup;
    }
    if (allowed_enctypes == NULL)
        allowed_enctypes = any_enctype;

    if (keytab != NULL)
      code = krb5_kt_resolve(context, keytab, &kt);
    else
      code = krb5_kt_default(context, &kt);
    if (code != 0)
        goto cleanup;

    code = pick_enctype_and_principal(context, kt, allowed_enctypes,
				      &enctype, &service_principal, entry);
    if (code != 0)
	goto cleanup;

    /* Conjure up a random session key */
    deref_keyblock_enctype(session_key) = enctype;
#if USING_HEIMDAL
    code = krb5_generate_random_keyblock(context, enctype, session_key);
#else
    code = krb5_c_make_random_key(context, enctype, session_key);
#endif
    if (code != 0)
        goto cleanup;

    populate_enc_tkt(session_key, client_principal, starttime, endtime,
		     enc_tkt_reply);

    code = encrypt_enc_tkt(context, service_principal, entry, ticket_reply,
			   enc_tkt_reply);
    if (code != 0)
	goto cleanup;

    code = populate_creds(context, service_principal, client_principal,
			  session_key, ticket_reply, enc_tkt_reply, creds);
    if (code != 0)
	goto cleanup;

    /* return creds */
    *out_creds = creds;
    creds = NULL;
cleanup:
    if (deref_enc_data(&ticket_reply->enc_part) != NULL)
        free(deref_enc_data(&ticket_reply->enc_part));
    krb5_free_keytab_entry_contents(context, entry);
    if (client_principal != NULL)
        krb5_free_principal(context, client_principal);
    if (service_principal != NULL)
        krb5_free_principal(context, service_principal);
    if (kt != NULL)
        krb5_kt_close(context, kt);
    if (creds != NULL)
	krb5_free_creds(context, creds);
    krb5_free_keyblock_contents(context, session_key);
    free_ticket(ticket_reply);
    free_enc_tkt_part(enc_tkt_reply);
    return code;
}
Ejemplo n.º 16
0
static krb5_error_code
pkinit_server_return_padata(krb5_context context,
			    krb5_pa_data * padata,
			    struct _krb5_db_entry_new * client,
			    krb5_data *req_pkt,
			    krb5_kdc_req * request,
			    krb5_kdc_rep * reply,
			    struct _krb5_key_data * client_key,
			    krb5_keyblock * encrypting_key,
			    krb5_pa_data ** send_pa,
			    preauth_get_entry_data_proc server_get_entry_data,
			    void *pa_plugin_context,
			    void **pa_request_context)
{
    krb5_error_code retval = 0;
    krb5_data scratch = {0, 0, NULL};
    krb5_pa_pk_as_req *reqp = NULL;
    krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
    int i = 0;

    unsigned char *subjectPublicKey = NULL;
    unsigned char *dh_pubkey = NULL, *server_key = NULL;
    unsigned int subjectPublicKey_len = 0;
    unsigned int server_key_len = 0, dh_pubkey_len = 0;

    krb5_kdc_dh_key_info dhkey_info;
    krb5_data *encoded_dhkey_info = NULL;
    krb5_pa_pk_as_rep *rep = NULL;
    krb5_pa_pk_as_rep_draft9 *rep9 = NULL;
    krb5_data *out_data = NULL;

    krb5_enctype enctype = -1;

    krb5_reply_key_pack *key_pack = NULL;
    krb5_reply_key_pack_draft9 *key_pack9 = NULL;
    krb5_data *encoded_key_pack = NULL;
    unsigned int num_types;
    krb5_cksumtype *cksum_types = NULL;

    pkinit_kdc_context plgctx;
    pkinit_kdc_req_context reqctx;

    int fixed_keypack = 0;

    *send_pa = NULL;
    if (padata == NULL || padata->length <= 0 || padata->contents == NULL)
	return 0;

    if (pa_request_context == NULL || *pa_request_context == NULL) {
	pkiDebug("missing request context \n");
	return EINVAL;
    }
    
    plgctx = pkinit_find_realm_context(context, pa_plugin_context,
				       request->server);
    if (plgctx == NULL) {
	pkiDebug("Unable to locate correct realm context\n");
	return ENOENT;
    }

    pkiDebug("pkinit_return_padata: entered!\n");
    reqctx = (pkinit_kdc_req_context)*pa_request_context;

    if (encrypting_key->contents) {
	free(encrypting_key->contents);
	encrypting_key->length = 0;
	encrypting_key->contents = NULL;
    }

    for(i = 0; i < request->nktypes; i++) {
	enctype = request->ktype[i];
	if (!krb5_c_valid_enctype(enctype))
	    continue;
	else {
	    pkiDebug("KDC picked etype = %d\n", enctype);
	    break;
	}
    }

    if (i == request->nktypes) {
	retval = KRB5KDC_ERR_ETYPE_NOSUPP;
	goto cleanup;
    }

    switch((int)reqctx->pa_type) {
	case KRB5_PADATA_PK_AS_REQ:
	    init_krb5_pa_pk_as_rep(&rep);
	    if (rep == NULL) {
		retval = ENOMEM;
		goto cleanup;
	    }
	    /* let's assume it's RSA. we'll reset it to DH if needed */
	    rep->choice = choice_pa_pk_as_rep_encKeyPack;
	    break;
	case KRB5_PADATA_PK_AS_REP_OLD:
	case KRB5_PADATA_PK_AS_REQ_OLD:
	    init_krb5_pa_pk_as_rep_draft9(&rep9);
	    if (rep9 == NULL) {
		retval = ENOMEM;
		goto cleanup;
	    }
	    rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
	    break;
	default:
	    retval = KRB5KDC_ERR_PREAUTH_FAILED;
	    goto cleanup;
    }

    if (reqctx->rcv_auth_pack != NULL &&
	    reqctx->rcv_auth_pack->clientPublicValue != NULL) {
	subjectPublicKey =
	    reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.data;
	subjectPublicKey_len =
	    reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.length;
	rep->choice = choice_pa_pk_as_rep_dhInfo;
    } else if (reqctx->rcv_auth_pack9 != NULL &&
		reqctx->rcv_auth_pack9->clientPublicValue != NULL) {
	subjectPublicKey =
	    reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.data;
	subjectPublicKey_len =
	    reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.length;
	rep9->choice = choice_pa_pk_as_rep_draft9_dhSignedData;
    }

    /* if this DH, then process finish computing DH key */
    if (rep != NULL && (rep->choice == choice_pa_pk_as_rep_dhInfo ||
	    rep->choice == choice_pa_pk_as_rep_draft9_dhSignedData)) {
	pkiDebug("received DH key delivery AS REQ\n");
	retval = server_process_dh(context, plgctx->cryptoctx,
	    reqctx->cryptoctx, plgctx->idctx, subjectPublicKey,
	    subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len, 
	    &server_key, &server_key_len);
	if (retval) {
	    pkiDebug("failed to process/create dh paramters\n");
	    goto cleanup;
	}
    }
	
    if ((rep9 != NULL &&
	    rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) ||
	(rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) {
	retval = pkinit_octetstring2key(context, enctype, server_key,
					server_key_len, encrypting_key);
	if (retval) {
	    pkiDebug("pkinit_octetstring2key failed: %s\n",
		     error_message(retval));
	    goto cleanup;
	}

	dhkey_info.subjectPublicKey.length = dh_pubkey_len;
	dhkey_info.subjectPublicKey.data = dh_pubkey;
	dhkey_info.nonce = request->nonce;
	dhkey_info.dhKeyExpiration = 0;

	retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info,
						   &encoded_dhkey_info);
	if (retval) {
	    pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
	    goto cleanup;
	}
#ifdef DEBUG_ASN1
	print_buffer_bin((unsigned char *)encoded_dhkey_info->data,
			 encoded_dhkey_info->length,
			 "/tmp/kdc_dh_key_info");
#endif

	switch ((int)padata->pa_type) {
	    case KRB5_PADATA_PK_AS_REQ:
		retval = cms_signeddata_create(context, plgctx->cryptoctx,
		    reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_SERVER, 1,
		    (unsigned char *)encoded_dhkey_info->data,
		    encoded_dhkey_info->length,
		    &rep->u.dh_Info.dhSignedData.data,
		    &rep->u.dh_Info.dhSignedData.length);
		if (retval) {
		    pkiDebug("failed to create pkcs7 signed data\n");
		    goto cleanup;
		}
		break;
	    case KRB5_PADATA_PK_AS_REP_OLD:
	    case KRB5_PADATA_PK_AS_REQ_OLD:
		retval = cms_signeddata_create(context, plgctx->cryptoctx,
		    reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9, 1,
		    (unsigned char *)encoded_dhkey_info->data,
		    encoded_dhkey_info->length,
		    &rep9->u.dhSignedData.data,
		    &rep9->u.dhSignedData.length);
		if (retval) {
		    pkiDebug("failed to create pkcs7 signed data\n");
		    goto cleanup;
		}
		break;
	}
    } else {
	pkiDebug("received RSA key delivery AS REQ\n");

	retval = krb5_c_make_random_key(context, enctype, encrypting_key);
	if (retval) {
	    pkiDebug("unable to make a session key\n");
	    goto cleanup;
	}

	/* check if PA_TYPE of 132 is present which means the client is
	 * requesting that a checksum is send back instead of the nonce
	 */
	for (i = 0; request->padata[i] != NULL; i++) {
	    pkiDebug("%s: Checking pa_type 0x%08x\n",
		     __FUNCTION__, request->padata[i]->pa_type);
	    if (request->padata[i]->pa_type == 132)
		fixed_keypack = 1;
	}
	pkiDebug("%s: return checksum instead of nonce = %d\n",
		 __FUNCTION__, fixed_keypack);

	/* if this is an RFC reply or draft9 client requested a checksum 
	 * in the reply instead of the nonce, create an RFC-style keypack
	 */
	if ((int)padata->pa_type == KRB5_PADATA_PK_AS_REQ || fixed_keypack) {
	    init_krb5_reply_key_pack(&key_pack);
	    if (key_pack == NULL) {
		retval = ENOMEM;
		goto cleanup;
	    }
	    /* retrieve checksums for a given enctype of the reply key */
	    retval = krb5_c_keyed_checksum_types(context,
		encrypting_key->enctype, &num_types, &cksum_types);
	    if (retval)
		goto cleanup;

	    /* pick the first of acceptable enctypes for the checksum */
	    retval = krb5_c_make_checksum(context, cksum_types[0],
		    encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
		    req_pkt, &key_pack->asChecksum);
	    if (retval) {
		pkiDebug("unable to calculate AS REQ checksum\n");
		goto cleanup;
	    }
#ifdef DEBUG_CKSUM
	    pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length);
	    print_buffer(req_pkt->data, req_pkt->length);
	    pkiDebug("checksum size = %d\n", key_pack->asChecksum.length);
	    print_buffer(key_pack->asChecksum.contents, 
			 key_pack->asChecksum.length);
	    pkiDebug("encrypting key (%d)\n", encrypting_key->length);
	    print_buffer(encrypting_key->contents, encrypting_key->length);
#endif

	    krb5_copy_keyblock_contents(context, encrypting_key,
					&key_pack->replyKey);

	    retval = k5int_encode_krb5_reply_key_pack(key_pack,
						      &encoded_key_pack);
	    if (retval) {
		pkiDebug("failed to encode reply_key_pack\n");
		goto cleanup;
	    }
	}

	switch ((int)padata->pa_type) {
	    case KRB5_PADATA_PK_AS_REQ:
		rep->choice = choice_pa_pk_as_rep_encKeyPack;
		retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
		    reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1, 
		    (unsigned char *)encoded_key_pack->data,
		    encoded_key_pack->length,
		    &rep->u.encKeyPack.data, &rep->u.encKeyPack.length);
		break;
	    case KRB5_PADATA_PK_AS_REP_OLD:
	    case KRB5_PADATA_PK_AS_REQ_OLD:
		/* if the request is from the broken draft9 client that
		 * expects back a nonce, create it now 
		 */
		if (!fixed_keypack) {
		    init_krb5_reply_key_pack_draft9(&key_pack9);
		    if (key_pack9 == NULL) {
			retval = ENOMEM;
			goto cleanup;
		    }
		    key_pack9->nonce = reqctx->rcv_auth_pack9->pkAuthenticator.nonce;
		    krb5_copy_keyblock_contents(context, encrypting_key,
						&key_pack9->replyKey);

		    retval = k5int_encode_krb5_reply_key_pack_draft9(key_pack9,
							   &encoded_key_pack);
		    if (retval) {
			pkiDebug("failed to encode reply_key_pack\n");
			goto cleanup;
		    }
		} 

		rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
		retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
		    reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1, 
		    (unsigned char *)encoded_key_pack->data,
		    encoded_key_pack->length,
		    &rep9->u.encKeyPack.data, &rep9->u.encKeyPack.length);
		break;
	}
	if (retval) {
	    pkiDebug("failed to create pkcs7 enveloped data: %s\n",
		     error_message(retval));
	    goto cleanup;
	}
#ifdef DEBUG_ASN1
	print_buffer_bin((unsigned char *)encoded_key_pack->data,
			 encoded_key_pack->length,
			 "/tmp/kdc_key_pack");
	switch ((int)padata->pa_type) {
	    case KRB5_PADATA_PK_AS_REQ:
		print_buffer_bin(rep->u.encKeyPack.data,
				 rep->u.encKeyPack.length,
				 "/tmp/kdc_enc_key_pack");
		break;
	    case KRB5_PADATA_PK_AS_REP_OLD:
	    case KRB5_PADATA_PK_AS_REQ_OLD:
		print_buffer_bin(rep9->u.encKeyPack.data,
				 rep9->u.encKeyPack.length,
				 "/tmp/kdc_enc_key_pack");
		break;
	}
#endif
    }

    switch ((int)padata->pa_type) {
	case KRB5_PADATA_PK_AS_REQ:
	    retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data);
	    break;
	case KRB5_PADATA_PK_AS_REP_OLD:
	case KRB5_PADATA_PK_AS_REQ_OLD:
	    retval = k5int_encode_krb5_pa_pk_as_rep_draft9(rep9, &out_data);
	    break;
    }
    if (retval) {
	pkiDebug("failed to encode AS_REP\n");
	goto cleanup;
    }
#ifdef DEBUG_ASN1
    if (out_data != NULL)
	print_buffer_bin((unsigned char *)out_data->data, out_data->length,
			 "/tmp/kdc_as_rep");
#endif

    *send_pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data));
    if (*send_pa == NULL) {
	retval = ENOMEM;
	free(out_data->data);
	free(out_data);
	out_data = NULL;
	goto cleanup;
    }
    (*send_pa)->magic = KV5M_PA_DATA;
    switch ((int)padata->pa_type) {
	case KRB5_PADATA_PK_AS_REQ:
	    (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
	    break;
	case KRB5_PADATA_PK_AS_REQ_OLD:
	case KRB5_PADATA_PK_AS_REP_OLD:
	    (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP_OLD;
	    break;
    }
    (*send_pa)->length = out_data->length;
    (*send_pa)->contents = (krb5_octet *) out_data->data;


  cleanup:
    pkinit_fini_kdc_req_context(context, reqctx);
    if (scratch.data != NULL)
	free(scratch.data);
    if (out_data != NULL)
	free(out_data);
    if (encoded_dhkey_info != NULL)
	krb5_free_data(context, encoded_dhkey_info);
    if (encoded_key_pack != NULL)
	krb5_free_data(context, encoded_key_pack);
    if (dh_pubkey != NULL)
	free(dh_pubkey);
    if (server_key != NULL)
	free(server_key);
    if (cksum_types != NULL)
	free(cksum_types);

    switch ((int)padata->pa_type) {
	case KRB5_PADATA_PK_AS_REQ:
	    free_krb5_pa_pk_as_req(&reqp);
	    free_krb5_pa_pk_as_rep(&rep);
	    free_krb5_reply_key_pack(&key_pack);
	    break;
	case KRB5_PADATA_PK_AS_REP_OLD:
	case KRB5_PADATA_PK_AS_REQ_OLD:
	    free_krb5_pa_pk_as_req_draft9(&reqp9);
	    free_krb5_pa_pk_as_rep_draft9(&rep9);
	    if (!fixed_keypack)
		free_krb5_reply_key_pack_draft9(&key_pack9);
	    else
		free_krb5_reply_key_pack(&key_pack);
	    break;
    }

    if (retval)
	pkiDebug("pkinit_verify_padata failure");

    return retval;
}
Ejemplo n.º 17
0
static char *
random_passwd(krb5_context ctx, int len)
{
	krb5_keyblock	 key;
	krb5_error_code	 ret;
	char		 croakstr[2048] = "";
	char		*passwd = NULL;
	unsigned char	*tmp;
	int		 i;

	passwd = malloc(len + 1);
	if (!passwd) {
		snprintf(croakstr, sizeof(croakstr), "Out of memory");
		ret = errno;
		goto done;
	}

	/* We lamely convert a key into a string for the passwd */
	K5BAIL(krb5_c_make_random_key(ctx, 18, &key));

	/*
	 * We are contructing what we presume to be a relatively good
	 * passwd here.  First, we select a single character from each
	 * of three character classes.  We do this up front to ensure
	 * that all passwds contain at least 3 character classes.  We
	 * could generate and then test, but we don't.  We looking to
	 * weight things a little away from the symbols and towards
	 * simplicity.  So, let's say that lower or upper case characters
	 * have about 4.5 bits of strength given that we've selected
	 * 23 of them.  The numbers have about 2.2 or so.  Our c_all[]
	 * is also a little skewed.  We have 79 possible characters but
	 * we're skewing towards lower case to make it easier to type.
	 * So, we're not really getting over 6 bits out of it.  Still,
	 * let's say that we're getting 5.5, then our 10 char passwd
	 * is:
	 *
	 *	2.2 + 4.5 + 4.5 + 7 * 5.5 = 49 bits.
	 *
	 * XXXrcd:
	 * Also note that because of our use of simple modulo arith,
	 * we're slightly biasing results towards the fronts of each
	 * of these character classes...
	 *
	 * Good enough.  Certainly better than the users will choose for
	 * themselves.
	 */

	tmp = KEYBLOCK_CONTENTS(key);
	passwd[0] = c_low[tmp[0] % (sizeof(c_low) - 1)];
	passwd[1] = c_cap[tmp[1] % (sizeof(c_cap) - 1)];
	passwd[2] = c_num[tmp[2] % (sizeof(c_num) - 1)];
	for (i=3; i < len; i++)
		passwd[i] = c_all[tmp[i] % (sizeof(c_all) - 1)];

	krb5_free_keyblock_contents(ctx, &key);
	passwd[i] = '\0';

done:
	if (ret) {
		free(passwd);
		croak("%s", croakstr);
	}

	return passwd;
}