Пример #1
0
krb5_error_code krb5int_confounder_verify(const struct krb5_cksumtypes *ctp,
                                          krb5_key key, krb5_keyusage usage,
                                          const krb5_crypto_iov *data,
                                          size_t num_data,
                                          const krb5_data *input,
                                          krb5_boolean *valid)
{
    krb5_error_code ret;
    unsigned char *plaintext = NULL;
    krb5_key xorkey = NULL;
    krb5_data computed = empty_data();
    krb5_crypto_iov *hash_iov = NULL, iov;
    size_t blocksize = ctp->enc->block_size, hashsize = ctp->hash->hashsize;

    plaintext = k5memdup(input->data, input->length, &ret);
    if (plaintext == NULL)
        return ret;

    ret = mk_xorkey(key, &xorkey);
    if (ret != 0)
        goto cleanup;

    /* Decrypt the input checksum. */
    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data = make_data(plaintext, input->length);
    ret = ctp->enc->decrypt(xorkey, NULL, &iov, 1);
    if (ret != 0)
        goto cleanup;

    /* Hash the confounder, then the input data. */
    hash_iov = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret);
    if (hash_iov == NULL)
        goto cleanup;
    hash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
    hash_iov[0].data = make_data(plaintext, blocksize);
    memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov));
    ret = alloc_data(&computed, hashsize);
    if (ret != 0)
        goto cleanup;
    ret = ctp->hash->hash(hash_iov, num_data + 1, &computed);
    if (ret != 0)
        goto cleanup;

    /* Compare the decrypted hash to the computed one. */
    *valid = (memcmp(plaintext + blocksize, computed.data, hashsize) == 0);

cleanup:
    zapfree(plaintext, input->length);
    zapfree(computed.data, hashsize);
    free(hash_iov);
    krb5_k_free_key(NULL, xorkey);
    return ret;
}
Пример #2
0
/* Derive a key by XOR with 0xF0 bytes. */
static krb5_error_code
mk_xorkey(krb5_key origkey, krb5_key *xorkey)
{
    krb5_error_code retval = 0;
    unsigned char *xorbytes;
    krb5_keyblock xorkeyblock;
    size_t i = 0;

    xorbytes = k5memdup(origkey->keyblock.contents, origkey->keyblock.length,
                        &retval);
    if (xorbytes == NULL)
        return retval;
    for (i = 0; i < origkey->keyblock.length; i++)
        xorbytes[i] ^= 0xf0;

    /* Do a shallow copy here. */
    xorkeyblock = origkey->keyblock;
    xorkeyblock.contents = xorbytes;

    retval = krb5_k_create_key(0, &xorkeyblock, xorkey);
    zapfree(xorbytes, sizeof(xorbytes));
    return retval;
}
Пример #3
0
krb5_error_code
krb5_add_ber_mem_ldap_mod(LDAPMod ***list, char *attribute, int op,
                          struct berval **ber_values)
{
    krb5_error_code ret;
    LDAPMod *mod;
    size_t count, i;

    ret = alloc_mod(list, &mod);
    if (ret)
        return ret;

    mod->mod_type = strdup(attribute);
    if (mod->mod_type == NULL)
        return ENOMEM;
    mod->mod_op = op;

    for (count = 0; ber_values[count] != NULL; count++);
    mod->mod_bvalues = calloc(count + 1, sizeof(struct berval *));
    if (mod->mod_bvalues == NULL)
        return ENOMEM;

    for (i = 0; i < count; i++) {
        mod->mod_bvalues[i] = calloc(1, sizeof(struct berval));
        if (mod->mod_bvalues[i] == NULL)
            return ENOMEM;

        mod->mod_bvalues[i]->bv_len = ber_values[i]->bv_len;
        mod->mod_bvalues[i]->bv_val = k5memdup(ber_values[i]->bv_val,
                                               ber_values[i]->bv_len, &ret);
        if (mod->mod_bvalues[i]->bv_val == NULL)
            return ret;
    }
    mod->mod_bvalues[i] = NULL;
    return 0;
}
Пример #4
0
krb5_error_code
k5_os_hostaddr(krb5_context context, const char *name,
               krb5_address ***ret_addrs)
{
    krb5_error_code     retval;
    krb5_address        **addrs;
    int                 i, j, r;
    struct addrinfo hints, *ai, *aip;

    if (!name)
        return KRB5_ERR_BAD_HOSTNAME;

    memset (&hints, 0, sizeof (hints));
    hints.ai_flags = AI_NUMERICHOST | AI_ADDRCONFIG;
    /* We don't care what kind at this point, really, but without
       this, we can get back multiple sockaddrs per address, for
       SOCK_DGRAM, SOCK_STREAM, and SOCK_RAW.  I haven't checked if
       that's what the spec indicates.  */
    hints.ai_socktype = SOCK_DGRAM;

    r = getaddrinfo (name, 0, &hints, &ai);
    if (r && AI_NUMERICHOST != 0) {
        hints.ai_flags &= ~AI_NUMERICHOST;
        r = getaddrinfo (name, 0, &hints, &ai);
    }
    if (r)
        return KRB5_ERR_BAD_HOSTNAME;

    for (i = 0, aip = ai; aip; aip = aip->ai_next) {
        switch (aip->ai_addr->sa_family) {
        case AF_INET:
        case AF_INET6:
            i++;
        default:
            /* Ignore addresses of unknown families.  */
            ;
        }
    }

    addrs = malloc ((i+1) * sizeof(*addrs));
    if (!addrs)
        return ENOMEM;

    for (j = 0; j < i + 1; j++)
        addrs[j] = 0;

    for (i = 0, aip = ai; aip; aip = aip->ai_next) {
        void *ptr;
        size_t addrlen;
        int atype;

        switch (aip->ai_addr->sa_family) {
        case AF_INET:
            addrlen = sizeof (struct in_addr);
            ptr = &sa2sin(aip->ai_addr)->sin_addr;
            atype = ADDRTYPE_INET;
            break;
        case AF_INET6:
            addrlen = sizeof (struct in6_addr);
            ptr = &sa2sin6(aip->ai_addr)->sin6_addr;
            atype = ADDRTYPE_INET6;
            break;
        default:
            continue;
        }
        addrs[i] = (krb5_address *) malloc(sizeof(krb5_address));
        if (!addrs[i]) {
            retval = ENOMEM;
            goto errout;
        }
        addrs[i]->magic = KV5M_ADDRESS;
        addrs[i]->addrtype = atype;
        addrs[i]->length = addrlen;
        addrs[i]->contents = k5memdup(ptr, addrlen, &retval);
        if (addrs[i]->contents == NULL)
            goto errout;
        i++;
    }

    *ret_addrs = addrs;
    if (ai)
        freeaddrinfo(ai);
    return 0;

errout:
    if (addrs) {
        for (i = 0; addrs[i]; i++) {
            free (addrs[i]->contents);
            free (addrs[i]);
        }
        krb5_free_addresses(context, addrs);
    }
    if (ai)
        freeaddrinfo(ai);
    return retval;

}
Пример #5
0
krb5_error_code
krb5_decode_princ_entry(krb5_context context, krb5_data *content,
                        krb5_db_entry **entry_ptr)
{
    int                   sizeleft, i;
    unsigned char       * nextloc;
    krb5_tl_data       ** tl_data;
    krb5_int16            i16;
    krb5_db_entry       * entry;
    krb5_error_code retval;

    *entry_ptr = NULL;

    entry = k5alloc(sizeof(*entry), &retval);
    if (entry == NULL)
        return retval;

    /*
     * Reverse the encoding of encode_princ_entry.
     *
     * The first part is decoding the base type. If the base type is
     * bigger than the original base type then the additional fields
     * need to be filled in. If the base type is larger than any
     * known base type the additional data goes in e_data.
     */

    /* First do the easy stuff */
    nextloc = (unsigned char *)content->data;
    sizeleft = content->length;
    if (sizeleft < KRB5_KDB_V1_BASE_LENGTH) {
        retval = KRB5_KDB_TRUNCATED_RECORD;
        goto error_out;
    }
    sizeleft -= KRB5_KDB_V1_BASE_LENGTH;

    /* Base Length */
    krb5_kdb_decode_int16(nextloc, entry->len);
    nextloc += 2;

    /* Attributes */
    krb5_kdb_decode_int32(nextloc, entry->attributes);
    nextloc += 4;

    /* Max Life */
    krb5_kdb_decode_int32(nextloc, entry->max_life);
    nextloc += 4;

    /* Max Renewable Life */
    krb5_kdb_decode_int32(nextloc, entry->max_renewable_life);
    nextloc += 4;

    /* When the client expires */
    krb5_kdb_decode_int32(nextloc, entry->expiration);
    nextloc += 4;

    /* When its passwd expires */
    krb5_kdb_decode_int32(nextloc, entry->pw_expiration);
    nextloc += 4;

    /* Last successful passwd */
    krb5_kdb_decode_int32(nextloc, entry->last_success);
    nextloc += 4;

    /* Last failed passwd attempt */
    krb5_kdb_decode_int32(nextloc, entry->last_failed);
    nextloc += 4;

    /* # of failed passwd attempt */
    krb5_kdb_decode_int32(nextloc, entry->fail_auth_count);
    nextloc += 4;

    /* # tl_data strutures */
    krb5_kdb_decode_int16(nextloc, entry->n_tl_data);
    nextloc += 2;

    if (entry->n_tl_data < 0) {
        retval = KRB5_KDB_TRUNCATED_RECORD;
        goto error_out;
    }

    /* # key_data strutures */
    krb5_kdb_decode_int16(nextloc, entry->n_key_data);
    nextloc += 2;

    if (entry->n_key_data < 0) {
        retval = KRB5_KDB_TRUNCATED_RECORD;
        goto error_out;
    }

    /* Check for extra data */
    if (entry->len > KRB5_KDB_V1_BASE_LENGTH) {
        entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH;
        entry->e_data = k5memdup(nextloc, entry->e_length, &retval);
        if (entry->e_data == NULL)
            goto error_out;
        nextloc += entry->e_length;
    }

    /*
     * Get the principal name for the entry
     * (stored as a string which gets unparsed.)
     */
    if (sizeleft < 2) {
        retval = KRB5_KDB_TRUNCATED_RECORD;
        goto error_out;
    }
    sizeleft -= 2;

    i = 0;
    krb5_kdb_decode_int16(nextloc, i16);
    i = (int) i16;
    nextloc += 2;
    if (i <= 0 || i > sizeleft || nextloc[i - 1] != '\0' ||
            memchr((char *)nextloc, '\0', i - 1) != NULL) {
        retval = KRB5_KDB_TRUNCATED_RECORD;
        goto error_out;
    }

    if ((retval = krb5_parse_name(context, (char *)nextloc, &(entry->princ))))
        goto error_out;
    sizeleft -= i;
    nextloc += i;

    /* tl_data is a linked list */
    tl_data = &entry->tl_data;
    for (i = 0; i < entry->n_tl_data; i++) {
        if (sizeleft < 4) {
            retval = KRB5_KDB_TRUNCATED_RECORD;
            goto error_out;
        }
        sizeleft -= 4;
        if ((*tl_data = (krb5_tl_data *)
                        malloc(sizeof(krb5_tl_data))) == NULL) {
            retval = ENOMEM;
            goto error_out;
        }
        (*tl_data)->tl_data_next = NULL;
        (*tl_data)->tl_data_contents = NULL;
        krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_type);
        nextloc += 2;
        krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_length);
        nextloc += 2;

        if ((*tl_data)->tl_data_length > sizeleft) {
            retval = KRB5_KDB_TRUNCATED_RECORD;
            goto error_out;
        }
        sizeleft -= (*tl_data)->tl_data_length;
        (*tl_data)->tl_data_contents =
            k5memdup(nextloc, (*tl_data)->tl_data_length, &retval);
        if ((*tl_data)->tl_data_contents == NULL)
            goto error_out;
        nextloc += (*tl_data)->tl_data_length;
        tl_data = &((*tl_data)->tl_data_next);
    }

    /* key_data is an array */
    if (entry->n_key_data && ((entry->key_data = (krb5_key_data *)
                               malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL)) {
        retval = ENOMEM;
        goto error_out;
    }
    for (i = 0; i < entry->n_key_data; i++) {
        krb5_key_data * key_data;
        int j;

        if (sizeleft < 4) {
            retval = KRB5_KDB_TRUNCATED_RECORD;
            goto error_out;
        }
        sizeleft -= 4;
        key_data = entry->key_data + i;
        memset(key_data, 0, sizeof(krb5_key_data));
        krb5_kdb_decode_int16(nextloc, key_data->key_data_ver);
        nextloc += 2;
        krb5_kdb_decode_int16(nextloc, key_data->key_data_kvno);
        nextloc += 2;

        /* key_data_ver determins number of elements and how to unparse them. */
        if (key_data->key_data_ver >= 0 &&
                key_data->key_data_ver <= KRB5_KDB_V1_KEY_DATA_ARRAY) {
            for (j = 0; j < key_data->key_data_ver; j++) {
                if (sizeleft < 4) {
                    retval = KRB5_KDB_TRUNCATED_RECORD;
                    goto error_out;
                }
                sizeleft -= 4;
                krb5_kdb_decode_int16(nextloc, key_data->key_data_type[j]);
                nextloc += 2;
                krb5_kdb_decode_int16(nextloc, key_data->key_data_length[j]);
                nextloc += 2;

                if (key_data->key_data_length[j] > sizeleft) {
                    retval = KRB5_KDB_TRUNCATED_RECORD;
                    goto error_out;
                }
                sizeleft -= key_data->key_data_length[j];
                if (key_data->key_data_length[j]) {
                    key_data->key_data_contents[j] =
                        k5memdup(nextloc, key_data->key_data_length[j],
                                 &retval);
                    if (key_data->key_data_contents[j] == NULL)
                        goto error_out;
                    nextloc += key_data->key_data_length[j];
                }
            }
        } else {
            retval = KRB5_KDB_BAD_VERSION;
            goto error_out;
        }
    }
    *entry_ptr = entry;
    return 0;

error_out:
    krb5_db_free_principal(context, entry);
    return retval;
}
Пример #6
0
/*
 * Construct a TGS request and return its ASN.1 encoding as well as the
 * timestamp, nonce, and subkey used.  The pacb_fn callback allows the caller
 * to amend the request padata after the nonce and subkey are determined.
 */
krb5_error_code
k5_make_tgs_req(krb5_context context,
                struct krb5int_fast_request_state *fast_state,
                krb5_creds *tgt, krb5_flags kdcoptions,
                krb5_address *const *addrs, krb5_pa_data **in_padata,
                krb5_creds *desired, k5_pacb_fn pacb_fn, void *pacb_data,
                krb5_data *req_asn1_out, krb5_timestamp *timestamp_out,
                krb5_int32 *nonce_out, krb5_keyblock **subkey_out)
{
    krb5_error_code ret;
    krb5_kdc_req req;
    krb5_data *authdata_asn1 = NULL, *req_body_asn1 = NULL;
    krb5_data *ap_req_asn1 = NULL, *tgs_req_asn1 = NULL;
    krb5_ticket *sec_ticket = NULL;
    krb5_ticket *sec_ticket_arr[2];
    krb5_timestamp time_now;
    krb5_pa_data **padata = NULL, *pa;
    krb5_keyblock *subkey = NULL;
    krb5_enc_data authdata_enc;
    krb5_enctype enctypes[2], *defenctypes = NULL;
    size_t count, i;

    *req_asn1_out = empty_data();
    *timestamp_out = 0;
    *nonce_out = 0;
    *subkey_out = NULL;
    memset(&req, 0, sizeof(req));
    memset(&authdata_enc, 0, sizeof(authdata_enc));

    /* tgt's client principal must match the desired client principal. */
    if (!krb5_principal_compare(context, tgt->client, desired->client))
        return KRB5_PRINC_NOMATCH;

    /* tgt must be an actual credential, not a template. */
    if (!tgt->ticket.length)
        return KRB5_NO_TKT_SUPPLIED;

    req.kdc_options = kdcoptions;
    req.server = desired->server;
    req.from = desired->times.starttime;
    req.till = desired->times.endtime ? desired->times.endtime :
        tgt->times.endtime;
    req.rtime = desired->times.renew_till;
    ret = krb5_timeofday(context, &time_now);
    if (ret)
        return ret;
    *nonce_out = req.nonce = (krb5_int32)time_now;
    *timestamp_out = time_now;

    req.addresses = (krb5_address **)addrs;

    /* Generate subkey. */
    ret = krb5_generate_subkey(context, &tgt->keyblock, &subkey);
    if (ret)
        return ret;
    TRACE_SEND_TGS_SUBKEY(context, subkey);

    ret = krb5int_fast_tgs_armor(context, fast_state, subkey, &tgt->keyblock,
                                 NULL, NULL);
    if (ret)
        goto cleanup;

    if (desired->authdata != NULL) {
        ret = encode_krb5_authdata(desired->authdata, &authdata_asn1);
        if (ret)
            goto cleanup;
        ret = krb5_encrypt_helper(context, subkey,
                                  KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY,
                                  authdata_asn1, &authdata_enc);
        if (ret)
            goto cleanup;
        req.authorization_data = authdata_enc;
    }

    if (desired->keyblock.enctype != ENCTYPE_NULL) {
        if (!krb5_c_valid_enctype(desired->keyblock.enctype)) {
            ret = KRB5_PROG_ETYPE_NOSUPP;
            goto cleanup;
        }
        enctypes[0] = desired->keyblock.enctype;
        enctypes[1] = ENCTYPE_NULL;
        req.ktype = enctypes;
        req.nktypes = 1;
    } else {
        /* Get the default TGS enctypes. */
        ret = krb5_get_tgs_ktypes(context, desired->server, &defenctypes);
        if (ret)
            goto cleanup;
        for (count = 0; defenctypes[count]; count++);
        req.ktype = defenctypes;
        req.nktypes = count;
    }
    TRACE_SEND_TGS_ETYPES(context, req.ktype);

    if (kdcoptions & (KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)) {
        if (desired->second_ticket.length == 0) {
            ret = KRB5_NO_2ND_TKT;
            goto cleanup;
        }
        ret = decode_krb5_ticket(&desired->second_ticket, &sec_ticket);
        if (ret)
            goto cleanup;
        sec_ticket_arr[0] = sec_ticket;
        sec_ticket_arr[1] = NULL;
        req.second_ticket = sec_ticket_arr;
    }

    /* Encode the request body. */
    ret = krb5int_fast_prep_req_body(context, fast_state, &req,
                                     &req_body_asn1);
    if (ret)
        goto cleanup;

    ret = tgs_construct_ap_req(context, req_body_asn1, tgt, subkey,
                               &ap_req_asn1);
    if (ret)
        goto cleanup;

    for (count = 0; in_padata != NULL && in_padata[count] != NULL; count++);

    /* Construct a padata array for the request, beginning with the ap-req. */
    padata = k5calloc(count + 2, sizeof(krb5_pa_data *), &ret);
    if (padata == NULL)
        goto cleanup;
    padata[0] = k5alloc(sizeof(krb5_pa_data), &ret);
    if (padata[0] == NULL)
        goto cleanup;
    padata[0]->pa_type = KRB5_PADATA_AP_REQ;
    padata[0]->contents = k5memdup(ap_req_asn1->data, ap_req_asn1->length,
                                   &ret);
    if (padata[0] == NULL)
        goto cleanup;
    padata[0]->length = ap_req_asn1->length;

    /* Append copies of any other supplied padata. */
    for (i = 0; in_padata != NULL && in_padata[i] != NULL; i++) {
        pa = k5alloc(sizeof(krb5_pa_data), &ret);
        if (pa == NULL)
            goto cleanup;
        pa->pa_type = in_padata[i]->pa_type;
        pa->length = in_padata[i]->length;
        pa->contents = k5memdup(in_padata[i]->contents, in_padata[i]->length,
                                &ret);
        if (pa->contents == NULL)
            goto cleanup;
        padata[i + 1] = pa;
    }
    req.padata = padata;

    if (pacb_fn != NULL) {
        ret = (*pacb_fn)(context, subkey, &req, pacb_data);
        if (ret)
            goto cleanup;
    }

    /* Encode the TGS-REQ.  Discard the krb5_data container. */
    ret = krb5int_fast_prep_req(context, fast_state, &req, ap_req_asn1,
                                encode_krb5_tgs_req, &tgs_req_asn1);
    if (ret)
        goto cleanup;
    *req_asn1_out = *tgs_req_asn1;
    free(tgs_req_asn1);
    tgs_req_asn1 = NULL;

    *subkey_out = subkey;
    subkey = NULL;

cleanup:
    krb5_free_data(context, authdata_asn1);
    krb5_free_data(context, req_body_asn1);
    krb5_free_data(context, ap_req_asn1);
    krb5_free_pa_data(context, req.padata);
    krb5_free_ticket(context, sec_ticket);
    krb5_free_data_contents(context, &authdata_enc.ciphertext);
    krb5_free_keyblock(context, subkey);
    free(defenctypes);
    return ret;
}
Пример #7
0
static int
kpasswd_sendto_msg_callback(SOCKET fd, void *data, krb5_data *message)
{
    krb5_error_code                     code = 0;
    struct sockaddr_storage             local_addr;
    krb5_address                        local_kaddr;
    struct sendto_callback_context      *ctx = data;
    GETSOCKNAME_ARG3_TYPE               addrlen;
    krb5_data                           output;

    memset (message, 0, sizeof(krb5_data));

    /*
     * We need the local addr from the connection socket
     */
    addrlen = sizeof(local_addr);

    if (getsockname(fd, ss2sa(&local_addr), &addrlen) < 0) {
        code = SOCKET_ERRNO;
        goto cleanup;
    }

    /* some brain-dead OS's don't return useful information from
     * the getsockname call.  Namely, windows and solaris.  */

    if (local_addr.ss_family == AF_INET &&
        ss2sin(&local_addr)->sin_addr.s_addr != 0) {
        local_kaddr.addrtype = ADDRTYPE_INET;
        local_kaddr.length = sizeof(ss2sin(&local_addr)->sin_addr);
        local_kaddr.contents = (krb5_octet *) &ss2sin(&local_addr)->sin_addr;
    } else if (local_addr.ss_family == AF_INET6 &&
               memcmp(ss2sin6(&local_addr)->sin6_addr.s6_addr,
                      in6addr_any.s6_addr, sizeof(in6addr_any.s6_addr)) != 0) {
        local_kaddr.addrtype = ADDRTYPE_INET6;
        local_kaddr.length = sizeof(ss2sin6(&local_addr)->sin6_addr);
        local_kaddr.contents = (krb5_octet *) &ss2sin6(&local_addr)->sin6_addr;
    } else {
        krb5_address **addrs;

        code = krb5_os_localaddr(ctx->context, &addrs);
        if (code)
            goto cleanup;

        local_kaddr.magic = addrs[0]->magic;
        local_kaddr.addrtype = addrs[0]->addrtype;
        local_kaddr.length = addrs[0]->length;
        local_kaddr.contents = k5memdup(addrs[0]->contents, addrs[0]->length,
                                        &code);
        krb5_free_addresses(ctx->context, addrs);
        if (local_kaddr.contents == NULL)
            goto cleanup;
    }


    /*
     * TBD:  Does this tamper w/ the auth context in such a way
     * to break us?  Yes - provide 1 per conn-state / host...
     */


    if ((code = krb5_auth_con_setaddrs(ctx->context, ctx->auth_context,
                                       &local_kaddr, NULL)))
        goto cleanup;

    ctx->auth_context->remote_seq_number = ctx->remote_seq_num;
    ctx->auth_context->local_seq_number = ctx->local_seq_num;

    if (ctx->set_password_for)
        code = krb5int_mk_setpw_req(ctx->context,
                                    ctx->auth_context,
                                    &ctx->ap_req,
                                    ctx->set_password_for,
                                    ctx->newpw,
                                    &output);
    else
        code = krb5int_mk_chpw_req(ctx->context,
                                   ctx->auth_context,
                                   &ctx->ap_req,
                                   ctx->newpw,
                                   &output);
    if (code)
        goto cleanup;

    message->length = output.length;
    message->data = output.data;

cleanup:
    return code;
}
Пример #8
0
krb5_error_code KRB5_CALLCONV
krb5_pac_sign(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
              krb5_const_principal principal, const krb5_keyblock *server_key,
              const krb5_keyblock *privsvr_key, krb5_data *data)
{
    krb5_error_code ret;
    krb5_data server_cksum, privsvr_cksum;
    krb5_cksumtype server_cksumtype, privsvr_cksumtype;
    krb5_crypto_iov iov[2];

    data->length = 0;
    data->data = NULL;

    if (principal != NULL) {
        ret = k5_insert_client_info(context, pac, authtime, principal);
        if (ret != 0)
            return ret;
    }

    /* Create zeroed buffers for both checksums */
    ret = k5_insert_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM,
                             server_key, &server_cksumtype);
    if (ret != 0)
        return ret;

    ret = k5_insert_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,
                             privsvr_key, &privsvr_cksumtype);
    if (ret != 0)
        return ret;

    /* Now, encode the PAC header so that the checksums will include it */
    ret = k5_pac_encode_header(context, pac);
    if (ret != 0)
        return ret;

    /* Generate the server checksum over the entire PAC */
    ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,
                               &server_cksum);
    if (ret != 0)
        return ret;

    assert(server_cksum.length > PAC_SIGNATURE_DATA_LENGTH);

    iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[0].data = pac->data;

    iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
    iov[1].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
    iov[1].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;

    ret = krb5_c_make_checksum_iov(context, server_cksumtype,
                                   server_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
                                   iov, sizeof(iov)/sizeof(iov[0]));
    if (ret != 0)
        return ret;

    /* Generate the privsvr checksum over the server checksum buffer */
    ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,
                               &privsvr_cksum);
    if (ret != 0)
        return ret;

    assert(privsvr_cksum.length > PAC_SIGNATURE_DATA_LENGTH);

    iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[0].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
    iov[0].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;

    iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
    iov[1].data.data = privsvr_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
    iov[1].data.length = privsvr_cksum.length - PAC_SIGNATURE_DATA_LENGTH;

    ret = krb5_c_make_checksum_iov(context, privsvr_cksumtype,
                                   privsvr_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
                                   iov, sizeof(iov)/sizeof(iov[0]));
    if (ret != 0)
        return ret;

    data->data = k5memdup(pac->data.data, pac->data.length, &ret);
    if (data->data == NULL)
        return ret;
    data->length = pac->data.length;

    memset(pac->data.data, 0,
           PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH));

    return 0;
}
Пример #9
0
krb5_error_code
kdc_find_fast(krb5_kdc_req **requestptr,
              krb5_data *checksummed_data,
              krb5_keyblock *tgs_subkey,
              krb5_keyblock *tgs_session,
              struct kdc_request_state *state,
              krb5_data **inner_body_out)
{
    krb5_error_code retval = 0;
    krb5_pa_data *fast_padata, *cookie_padata = NULL;
    krb5_data scratch, *inner_body = NULL;
    krb5_fast_req * fast_req = NULL;
    krb5_kdc_req *request = *requestptr;
    krb5_fast_armored_req *fast_armored_req = NULL;
    krb5_checksum *cksum;
    krb5_boolean cksum_valid;
    krb5_keyblock empty_keyblock;
    kdc_realm_t *kdc_active_realm = state->realm_data;

    if (inner_body_out != NULL)
        *inner_body_out = NULL;
    scratch.data = NULL;
    krb5_clear_error_message(kdc_context);
    memset(&empty_keyblock, 0, sizeof(krb5_keyblock));
    fast_padata = krb5int_find_pa_data(kdc_context,
                                       request->padata, KRB5_PADATA_FX_FAST);
    if (fast_padata !=  NULL){
        scratch.length = fast_padata->length;
        scratch.data = (char *) fast_padata->contents;
        retval = decode_krb5_pa_fx_fast_request(&scratch, &fast_armored_req);
        if (retval == 0 &&fast_armored_req->armor) {
            switch (fast_armored_req->armor->armor_type) {
            case KRB5_FAST_ARMOR_AP_REQUEST:
                if (tgs_subkey) {
                    retval = KRB5KDC_ERR_PREAUTH_FAILED;
                    krb5_set_error_message(kdc_context, retval,
                                           _("Ap-request armor not permitted "
                                             "with TGS"));
                    break;
                }
                retval = armor_ap_request(state, fast_armored_req->armor);
                break;
            default:
                krb5_set_error_message(kdc_context, KRB5KDC_ERR_PREAUTH_FAILED,
                                       _("Unknown FAST armor type %d"),
                                       fast_armored_req->armor->armor_type);
                retval = KRB5KDC_ERR_PREAUTH_FAILED;
            }
        }
        if (retval == 0 && !state->armor_key) {
            if (tgs_subkey)
                retval = krb5_c_fx_cf2_simple(kdc_context,
                                              tgs_subkey, "subkeyarmor",
                                              tgs_session, "ticketarmor",
                                              &state->armor_key);
            else {
                retval = KRB5KDC_ERR_PREAUTH_FAILED;
                krb5_set_error_message(kdc_context, retval,
                                       _("No armor key but FAST armored "
                                         "request present"));
            }
        }
        if (retval == 0) {
            krb5_data plaintext;
            plaintext.length = fast_armored_req->enc_part.ciphertext.length;
            plaintext.data = malloc(plaintext.length);
            if (plaintext.data == NULL)
                retval = ENOMEM;
            retval = krb5_c_decrypt(kdc_context,
                                    state->armor_key,
                                    KRB5_KEYUSAGE_FAST_ENC, NULL,
                                    &fast_armored_req->enc_part,
                                    &plaintext);
            if (retval == 0)
                retval = decode_krb5_fast_req(&plaintext, &fast_req);
            if (retval == 0 && inner_body_out != NULL) {
                retval = fetch_asn1_field((unsigned char *)plaintext.data,
                                          1, 2, &scratch);
                if (retval == 0) {
                    retval = krb5_copy_data(kdc_context, &scratch,
                                            &inner_body);
                }
            }
            if (plaintext.data)
                free(plaintext.data);
        }
        cksum = &fast_armored_req->req_checksum;
        if (retval == 0)
            retval = krb5_c_verify_checksum(kdc_context, state->armor_key,
                                            KRB5_KEYUSAGE_FAST_REQ_CHKSUM,
                                            checksummed_data, cksum,
                                            &cksum_valid);
        if (retval == 0 && !cksum_valid) {
            retval = KRB5KRB_AP_ERR_MODIFIED;
            krb5_set_error_message(kdc_context, retval,
                                   _("FAST req_checksum invalid; request "
                                     "modified"));
        }
        if (retval == 0) {
            if (!krb5_c_is_keyed_cksum(cksum->checksum_type)) {
                retval = KRB5KDC_ERR_POLICY;
                krb5_set_error_message(kdc_context, retval,
                                       _("Unkeyed checksum used in fast_req"));
            }
        }
        if (retval == 0) {
            if ((fast_req->fast_options & UNSUPPORTED_CRITICAL_FAST_OPTIONS) != 0)
                retval = KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION;
        }
        if (retval == 0)
            cookie_padata = krb5int_find_pa_data(kdc_context,
                                                 fast_req->req_body->padata,
                                                 KRB5_PADATA_FX_COOKIE);
        if (retval == 0) {
            state->fast_options = fast_req->fast_options;
            fast_req->req_body->msg_type = request->msg_type;
            krb5_free_kdc_req( kdc_context, request);
            *requestptr = fast_req->req_body;
            fast_req->req_body = NULL;
        }
    }
    else {
        cookie_padata = krb5int_find_pa_data(kdc_context,
                                             request->padata,
                                             KRB5_PADATA_FX_COOKIE);
    }
    if (retval == 0 && cookie_padata != NULL) {
        krb5_pa_data *new_padata = malloc(sizeof (krb5_pa_data));
        if (new_padata == NULL) {
            retval = ENOMEM;
        } else {
            new_padata->pa_type = KRB5_PADATA_FX_COOKIE;
            new_padata->length = cookie_padata->length;
            new_padata->contents =
                k5memdup(cookie_padata->contents, new_padata->length, &retval);
            if (new_padata->contents == NULL)
                free(new_padata);
            else
                state->cookie = new_padata;
        }
    }
    if (retval == 0 && inner_body_out != NULL) {
        *inner_body_out = inner_body;
        inner_body = NULL;
    }
    krb5_free_data(kdc_context, inner_body);
    if (fast_req)
        krb5_free_fast_req( kdc_context, fast_req);
    if (fast_armored_req)
        krb5_free_fast_armored_req(kdc_context, fast_armored_req);
    return retval;
}
Пример #10
0
static krb5_error_code
process_db_args(krb5_context context, char **db_args, xargs_t *xargs,
                OPERATION optype)
{
    int                   i=0;
    krb5_error_code       st=0;
    char                  *arg=NULL, *arg_val=NULL;
    char                  **dptr=NULL;
    unsigned int          arg_val_len=0;

    if (db_args) {
        for (i=0; db_args[i]; ++i) {
            arg = strtok_r(db_args[i], "=", &arg_val);
            if (strcmp(arg, TKTPOLICY_ARG) == 0) {
                dptr = &xargs->tktpolicydn;
            } else {
                if (strcmp(arg, USERDN_ARG) == 0) {
                    if (optype == MODIFY_PRINCIPAL ||
                        xargs->dn != NULL || xargs->containerdn != NULL ||
                        xargs->linkdn != NULL) {
                        st = EINVAL;
                        krb5_set_error_message(context, st,
                                               _("%s option not supported"),
                                               arg);
                        goto cleanup;
                    }
                    dptr = &xargs->dn;
                } else if (strcmp(arg, CONTAINERDN_ARG) == 0) {
                    if (optype == MODIFY_PRINCIPAL ||
                        xargs->dn != NULL || xargs->containerdn != NULL) {
                        st = EINVAL;
                        krb5_set_error_message(context, st,
                                               _("%s option not supported"),
                                               arg);
                        goto cleanup;
                    }
                    dptr = &xargs->containerdn;
                } else if (strcmp(arg, LINKDN_ARG) == 0) {
                    if (xargs->dn != NULL || xargs->linkdn != NULL) {
                        st = EINVAL;
                        krb5_set_error_message(context, st,
                                               _("%s option not supported"),
                                               arg);
                        goto cleanup;
                    }
                    dptr = &xargs->linkdn;
                } else {
                    st = EINVAL;
                    krb5_set_error_message(context, st,
                                           _("unknown option: %s"), arg);
                    goto cleanup;
                }

                xargs->dn_from_kbd = TRUE;
                if (arg_val == NULL || strlen(arg_val) == 0) {
                    st = EINVAL;
                    krb5_set_error_message(context, st,
                                           _("%s option value missing"), arg);
                    goto cleanup;
                }
            }

            if (arg_val == NULL) {
                st = EINVAL;
                krb5_set_error_message(context, st,
                                       _("%s option value missing"), arg);
                goto cleanup;
            }
            arg_val_len = strlen(arg_val) + 1;

            if (strcmp(arg, TKTPOLICY_ARG) == 0) {
                if ((st = krb5_ldap_name_to_policydn (context,
                                                      arg_val,
                                                      dptr)) != 0)
                    goto cleanup;
            } else {
                *dptr = k5memdup(arg_val, arg_val_len, &st);
                if (*dptr == NULL)
                    goto cleanup;
            }
        }
    }

cleanup:
    return st;
}