krb5_error_code KRB5_CALLCONV
krb5_calculate_checksum(krb5_context context, krb5_cksumtype ctype,
			krb5_const_pointer in, size_t in_length,
			krb5_const_pointer seed, size_t seed_length,
			krb5_checksum *outcksum)
{
    krb5_data input;
    krb5_keyblock key;
    krb5_error_code ret;
    krb5_checksum cksum;

    input.data = in;
    input.length = in_length;

    key.length = seed_length;
    key.contents = seed;

    if ((ret = krb5_c_make_checksum(context, ctype, &key, 0, &input, &cksum)))
	return(ret);

    if (outcksum->length < cksum.length) {
	memset(cksum.contents, 0, cksum.length);
	free(cksum.contents);
	return(KRB5_BAD_MSIZE);
    }

    outcksum->magic = cksum.magic;
    outcksum->checksum_type = cksum.checksum_type;
    memcpy(outcksum->contents, cksum.contents, cksum.length);
    outcksum->length = cksum.length;

    free(cksum.contents);
    
    return(0);
}
Exemple #2
0
/* Generate a response authenticator field. */
static krb5_error_code
auth_generate_response(krb5_context ctx, const char *secret,
                       const krad_packet *response, const uchar *auth,
                       uchar *rauth)
{
    krb5_error_code retval;
    krb5_checksum hash;
    krb5_data data;

    /* Allocate the temporary buffer. */
    retval = alloc_data(&data, response->pkt.length + strlen(secret));
    if (retval != 0)
        return retval;

    /* Encoded RADIUS packet with the request's
     * authenticator and the secret at the end. */
    memcpy(data.data, response->pkt.data, response->pkt.length);
    memcpy(data.data + OFFSET_AUTH, auth, AUTH_FIELD_SIZE);
    memcpy(data.data + response->pkt.length, secret, strlen(secret));

    /* Hash it. */
    retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
                                  &hash);
    free(data.data);
    if (retval != 0)
        return retval;

    memcpy(rauth, hash.contents, AUTH_FIELD_SIZE);
    krb5_free_checksum_contents(ctx, &hash);
    return 0;
}
Exemple #3
0
krb5_error_code
securid_make_sam_challenge_2_and_cksum(krb5_context context,
                                       krb5_sam_challenge_2 *sc2,
                                       krb5_sam_challenge_2_body *sc2b,
                                       krb5_keyblock *cksum_key)
{
    krb5_error_code retval;
    krb5_checksum **cksum_array = NULL;
    krb5_checksum *cksum = NULL;
    krb5_cksumtype cksumtype;
    krb5_data *encoded_challenge_body = NULL;

    if (!cksum_key)
        return KRB5_PREAUTH_NO_KEY;
    if (!sc2 || !sc2b)
        return KRB5KDC_ERR_PREAUTH_FAILED;

    retval = encode_krb5_sam_challenge_2_body(sc2b, &encoded_challenge_body);
    if (retval || !encoded_challenge_body) {
        encoded_challenge_body = NULL;
        goto cksum_cleanup;
    }

    cksum_array = calloc(2, sizeof(krb5_checksum *));
    if (!cksum_array) {
        retval = ENOMEM;
        goto cksum_cleanup;
    }

    cksum = (krb5_checksum *)k5alloc(sizeof(krb5_checksum), &retval);
    if (retval)
        goto cksum_cleanup;
    cksum_array[0] = cksum;
    cksum_array[1] = NULL;

    retval = krb5int_c_mandatory_cksumtype(context, cksum_key->enctype,
                                           &cksumtype);
    if (retval)
        goto cksum_cleanup;

    retval = krb5_c_make_checksum(context, cksumtype, cksum_key,
                                  KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
                                  encoded_challenge_body, cksum);
    if (retval)
        goto cksum_cleanup;

    sc2->sam_cksum = cksum_array;
    sc2->sam_challenge_2_body = *encoded_challenge_body;
    return 0;

cksum_cleanup:
    krb5_free_data(context, encoded_challenge_body);
    free(cksum_array);
    free(cksum);
    return retval;
}
Exemple #4
0
krb5_error_code KRB5_CALLCONV
krb5_c_verify_checksum(krb5_context context, const krb5_keyblock *key,
		    krb5_keyusage usage, const krb5_data *data,
		    const krb5_checksum *cksum, krb5_boolean *valid)
{
    int i;
    size_t hashsize;
    krb5_error_code ret;
    krb5_data indata;
    krb5_checksum computed;

    for (i=0; i<krb5_cksumtypes_length; i++) {
	if (krb5_cksumtypes_list[i].ctype == cksum->checksum_type)
	    break;
    }

    if (i == krb5_cksumtypes_length)
	return(KRB5_BAD_ENCTYPE);

    /* if there's actually a verify function, call it */

    indata.length = cksum->length;
    indata.data = (char *) cksum->contents;
    *valid = 0;

    if (krb5_cksumtypes_list[i].keyhash &&
	krb5_cksumtypes_list[i].keyhash->verify)
	return((*(krb5_cksumtypes_list[i].keyhash->verify))(
		context, key, usage, 0, data, &indata, valid));

    /* otherwise, make the checksum again, and compare */

    if ((ret = krb5_c_checksum_length(context, cksum->checksum_type, &hashsize)))
	return(ret);

    if (cksum->length != hashsize)
	return(KRB5_BAD_MSIZE);

    computed.length = hashsize;

    if ((ret = krb5_c_make_checksum(context, cksum->checksum_type, key, usage,
				   data, &computed))) {
	FREE(computed.contents, computed.length);
	return(ret);
    }

    *valid = (memcmp(computed.contents, cksum->contents, hashsize) == 0);

    FREE(computed.contents, computed.length);

    return(0);
}
Exemple #5
0
static krb5_error_code
make_ad_signedpath_checksum(krb5_context context,
                            krb5_const_principal for_user_princ,
                            const krb5_db_entry *krbtgt,
                            krb5_keyblock *krbtgt_key,
                            krb5_enc_tkt_part *enc_tkt_part,
                            krb5_principal *deleg_path,
                            krb5_pa_data **method_data,
                            krb5_checksum *cksum)
{
    krb5_error_code                 code;
    krb5_data                      *data;
    krb5_cksumtype                  cksumtype;
    krb5_const_principal            client;

    if (for_user_princ != NULL)
        client = for_user_princ;
    else
        client = enc_tkt_part->client;

    code = make_ad_signedpath_data(context,
                                   client,
                                   enc_tkt_part->times.authtime,
                                   deleg_path,
                                   method_data,
                                   enc_tkt_part->authorization_data,
                                   &data);
    if (code != 0)
        return code;

    code = krb5int_c_mandatory_cksumtype(context,
                                         krbtgt_key->enctype,
                                         &cksumtype);
    if (code != 0) {
        krb5_free_data(context, data);
        return code;
    }

    if (!krb5_c_is_keyed_cksum(cksumtype)) {
        krb5_free_data(context, data);
        return KRB5KRB_AP_ERR_INAPP_CKSUM;
    }

    code = krb5_c_make_checksum(context, cksumtype, krbtgt_key,
                                KRB5_KEYUSAGE_AD_SIGNEDPATH, data,
                                cksum);

    krb5_free_data(context, data);

    return code;
}
Exemple #6
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_c_verify_checksum(krb5_context context, const krb5_keyblock *key,
		       krb5_keyusage usage, const krb5_data *data,
		       const krb5_checksum *cksum, krb5_boolean *valid)
{
    krb5_error_code ret;
    krb5_checksum data_cksum;

    *valid = 0;

    ret = krb5_c_make_checksum(context, cksum->cksumtype,
			       key, usage, data, &data_cksum);
    if (ret)
	return ret;

    if (data_cksum.cksumtype == cksum->cksumtype
	&& krb5_data_ct_cmp(&data_cksum.checksum, &cksum->checksum) == 0)
	*valid = 1;

    krb5_free_checksum_contents(context, &data_cksum);

    return 0;
}
Exemple #7
0
/* Construct an AP-REQ message for a TGS request. */
static krb5_error_code
tgs_construct_ap_req(krb5_context context, krb5_data *checksum_data,
                     krb5_creds *tgt, krb5_keyblock *subkey,
                     krb5_data **ap_req_asn1_out)
{
    krb5_cksumtype cksumtype;
    krb5_error_code ret;
    krb5_checksum checksum;
    krb5_authenticator authent;
    krb5_ap_req ap_req;
    krb5_data *authent_asn1 = NULL;
    krb5_ticket *ticket = NULL;
    krb5_enc_data authent_enc;

    *ap_req_asn1_out = NULL;
    memset(&checksum, 0, sizeof(checksum));
    memset(&ap_req, 0, sizeof(ap_req));
    memset(&authent_enc, 0, sizeof(authent_enc));

    /* Determine the authenticator checksum type. */
    switch (tgt->keyblock.enctype) {
    case ENCTYPE_DES_CBC_CRC:
    case ENCTYPE_DES_CBC_MD4:
    case ENCTYPE_DES_CBC_MD5:
    case ENCTYPE_ARCFOUR_HMAC:
    case ENCTYPE_ARCFOUR_HMAC_EXP:
        cksumtype = context->kdc_req_sumtype;
        break;
    default:
        ret = krb5int_c_mandatory_cksumtype(context, tgt->keyblock.enctype,
                                            &cksumtype);
        if (ret)
            goto cleanup;
    }

    /* Generate checksum. */
    ret = krb5_c_make_checksum(context, cksumtype, &tgt->keyblock,
                               KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, checksum_data,
                               &checksum);
    if (ret)
        goto cleanup;

    /* Construct, encode, and encrypt an authenticator. */
    authent.subkey = subkey;
    authent.seq_number = 0;
    authent.checksum = &checksum;
    authent.client = tgt->client;
    authent.authorization_data = tgt->authdata;
    ret = krb5_us_timeofday(context, &authent.ctime, &authent.cusec);
    if (ret)
        goto cleanup;
    ret = encode_krb5_authenticator(&authent, &authent_asn1);
    if (ret)
        goto cleanup;
    ret = krb5_encrypt_helper(context, &tgt->keyblock,
                              KRB5_KEYUSAGE_TGS_REQ_AUTH, authent_asn1,
                              &authent_enc);
    if (ret)
        goto cleanup;

    ret = decode_krb5_ticket(&tgt->ticket, &ticket);
    if (ret)
        goto cleanup;

    /* Encode the AP-REQ. */
    ap_req.authenticator = authent_enc;
    ap_req.ticket = ticket;
    ret = encode_krb5_ap_req(&ap_req, ap_req_asn1_out);

cleanup:
    free(checksum.contents);
    krb5_free_ticket(context, ticket);
    krb5_free_data_contents(context, &authent_enc.ciphertext);
    if (authent_asn1 != NULL)
        zapfree(authent_asn1->data, authent_asn1->length);
    free(authent_asn1);
    return ret;
}
Exemple #8
0
krb5_error_code
krb5int_fast_prep_req(krb5_context context,
                      struct krb5int_fast_request_state *state,
                      krb5_kdc_req *request,
                      const krb5_data *to_be_checksummed,
                      kdc_req_encoder_proc encoder,
                      krb5_data **encoded_request)
{
    krb5_error_code retval = 0;
    krb5_pa_data *pa_array[2];
    krb5_pa_data pa[2];
    krb5_fast_req fast_req;
    krb5_fast_armored_req *armored_req = NULL;
    krb5_data *encoded_fast_req = NULL;
    krb5_data *encoded_armored_req = NULL;
    krb5_data *local_encoded_result = NULL;
    krb5_data random_data;
    char random_buf[4];

    assert(state != NULL);
    assert(state->fast_outer_request.padata == NULL);
    memset(pa_array, 0, sizeof pa_array);
    if (state->armor_key == NULL) {
        return encoder(request, encoded_request);
    }

    TRACE_FAST_ENCODE(context);
    /* Fill in a fresh random nonce for each inner request*/
    random_data.length = 4;
    random_data.data = (char *)random_buf;
    retval = krb5_c_random_make_octets(context, &random_data);
    if (retval == 0) {
        request->nonce = 0x7fffffff & load_32_n(random_buf);
        state->nonce = request->nonce;
    }
    fast_req.req_body =  request;
    if (fast_req.req_body->padata == NULL) {
        fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *));
        if (fast_req.req_body->padata == NULL)
            retval = ENOMEM;
    }
    fast_req.fast_options = state->fast_options;
    if (retval == 0)
        retval = encode_krb5_fast_req(&fast_req, &encoded_fast_req);
    if (retval == 0) {
        armored_req = calloc(1, sizeof(krb5_fast_armored_req));
        if (armored_req == NULL)
            retval = ENOMEM;
    }
    if (retval == 0)
        armored_req->armor = state->armor;
    if (retval ==0)
        retval = krb5_c_make_checksum(context, 0, state->armor_key,
                                      KRB5_KEYUSAGE_FAST_REQ_CHKSUM,
                                      to_be_checksummed,
                                      &armored_req->req_checksum);
    if (retval == 0)
        retval = krb5_encrypt_helper(context, state->armor_key,
                                     KRB5_KEYUSAGE_FAST_ENC, encoded_fast_req,
                                     &armored_req->enc_part);
    if (retval == 0)
        retval = encode_krb5_pa_fx_fast_request(armored_req,
                                                &encoded_armored_req);
    if (retval==0) {
        pa[0].pa_type = KRB5_PADATA_FX_FAST;
        pa[0].contents = (unsigned char *) encoded_armored_req->data;
        pa[0].length = encoded_armored_req->length;
        pa_array[0] = &pa[0];
    }
    state->fast_outer_request.padata = pa_array;
    if(retval == 0)
        retval = encoder(&state->fast_outer_request, &local_encoded_result);
    if (retval == 0) {
        *encoded_request = local_encoded_result;
        local_encoded_result = NULL;
    }
    if (encoded_armored_req)
        krb5_free_data(context, encoded_armored_req);
    if (armored_req) {
        armored_req->armor = NULL; /*owned by state*/
        krb5_free_fast_armored_req(context, armored_req);
    }
    if (encoded_fast_req)
        krb5_free_data(context, encoded_fast_req);
    if (local_encoded_result)
        krb5_free_data(context, local_encoded_result);
    state->fast_outer_request.padata = NULL;
    return retval;
}
Exemple #9
0
krb5_error_code
gss_krb5int_make_seal_token_v3 (krb5_context context,
                                krb5_gss_ctx_id_rec *ctx,
                                const gss_buffer_desc * message,
                                gss_buffer_t token,
                                int conf_req_flag, int toktype)
{
    size_t bufsize = 16;
    unsigned char *outbuf = 0;
    krb5_error_code err;
    int key_usage;
    unsigned char acceptor_flag;
    const gss_buffer_desc *message2 = message;
#ifdef CFX_EXERCISE
    size_t rrc;
#endif
    size_t ec;
    unsigned short tok_id;
    krb5_checksum sum;
    krb5_keyblock *key;
    krb5_cksumtype cksumtype;

    assert(ctx->big_endian == 0);

    acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
    key_usage = (toktype == KG_TOK_WRAP_MSG
                 ? (ctx->initiate
                    ? KG_USAGE_INITIATOR_SEAL
                    : KG_USAGE_ACCEPTOR_SEAL)
                 : (ctx->initiate
                    ? KG_USAGE_INITIATOR_SIGN
                    : KG_USAGE_ACCEPTOR_SIGN));
    if (ctx->have_acceptor_subkey) {
        key = ctx->acceptor_subkey;
        cksumtype = ctx->acceptor_subkey_cksumtype;
    } else {
        key = ctx->subkey;
        cksumtype = ctx->cksumtype;
    }
    assert(key != NULL);

#ifdef CFX_EXERCISE
    {
        static int initialized = 0;
        if (!initialized) {
            srand(time(0));
            initialized = 1;
        }
    }
#endif

    if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
        krb5_data plain;
        krb5_enc_data cipher;
        size_t ec_max;

        /* 300: Adds some slop.  */
        if (SIZE_MAX - 300 < message->length)
            return ENOMEM;
        ec_max = SIZE_MAX - message->length - 300;
        if (ec_max > 0xffff)
            ec_max = 0xffff;
#ifdef CFX_EXERCISE
        /* For testing only.  For performance, always set ec = 0.  */
        ec = ec_max & rand();
#else
        ec = 0;
#endif
        plain.length = message->length + 16 + ec;
        plain.data = malloc(message->length + 16 + ec);
        if (plain.data == NULL)
            return ENOMEM;

        /* Get size of ciphertext.  */
        bufsize = 16 + krb5_encrypt_size (plain.length, key->enctype);
        /* Allocate space for header plus encrypted data.  */
        outbuf = malloc(bufsize);
        if (outbuf == NULL) {
            free(plain.data);
            return ENOMEM;
        }

        /* TOK_ID */
        store_16_be(KG2_TOK_WRAP_MSG, outbuf);
        /* flags */
        outbuf[2] = (acceptor_flag
                     | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
                     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
        /* filler */
        outbuf[3] = 0xff;
        /* EC */
        store_16_be(ec, outbuf+4);
        /* RRC */
        store_16_be(0, outbuf+6);
        store_64_be(ctx->seq_send, outbuf+8);

        memcpy(plain.data, message->value, message->length);
        memset(plain.data + message->length, 'x', ec);
        memcpy(plain.data + message->length + ec, outbuf, 16);

        cipher.ciphertext.data = (char *)outbuf + 16;
        cipher.ciphertext.length = bufsize - 16;
        cipher.enctype = key->enctype;
        err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher);
        zap(plain.data, plain.length);
        free(plain.data);
        plain.data = 0;
        if (err)
            goto error;

        /* Now that we know we're returning a valid token....  */
        ctx->seq_send++;

#ifdef CFX_EXERCISE
        rrc = rand() & 0xffff;
        if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
                        (bufsize-16) - (rrc % (bufsize - 16))))
            store_16_be(rrc, outbuf+6);
        /* If the rotate fails, don't worry about it.  */
#endif
    } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
        krb5_data plain;
        size_t cksumsize;

        /* Here, message is the application-supplied data; message2 is
           what goes into the output token.  They may be the same, or
           message2 may be empty (for MIC).  */

        tok_id = KG2_TOK_WRAP_MSG;

    wrap_with_checksum:
        plain.length = message->length + 16;
        plain.data = malloc(message->length + 16);
        if (plain.data == NULL)
            return ENOMEM;

        err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
        if (err)
            goto error;

        assert(cksumsize <= 0xffff);

        bufsize = 16 + message2->length + cksumsize;
        outbuf = malloc(bufsize);
        if (outbuf == NULL) {
            free(plain.data);
            plain.data = 0;
            err = ENOMEM;
            goto error;
        }

        /* TOK_ID */
        store_16_be(tok_id, outbuf);
        /* flags */
        outbuf[2] = (acceptor_flag
                     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
        /* filler */
        outbuf[3] = 0xff;
        if (toktype == KG_TOK_WRAP_MSG) {
            /* Use 0 for checksum calculation, substitute
               checksum length later.  */
            /* EC */
            store_16_be(0, outbuf+4);
            /* RRC */
            store_16_be(0, outbuf+6);
        } else {
            /* MIC and DEL store 0xFF in EC and RRC.  */
            store_16_be(0xffff, outbuf+4);
            store_16_be(0xffff, outbuf+6);
        }
        store_64_be(ctx->seq_send, outbuf+8);

        memcpy(plain.data, message->value, message->length);
        memcpy(plain.data + message->length, outbuf, 16);

        /* Fill in the output token -- data contents, if any, and
           space for the checksum.  */
        if (message2->length)
            memcpy(outbuf + 16, message2->value, message2->length);

        sum.contents = outbuf + 16 + message2->length;
        sum.length = cksumsize;

        err = krb5_c_make_checksum(context, cksumtype, key,
                                   key_usage, &plain, &sum);
        zap(plain.data, plain.length);
        free(plain.data);
        plain.data = 0;
        if (err) {
            zap(outbuf,bufsize);
            goto error;
        }
        if (sum.length != cksumsize)
            abort();
        memcpy(outbuf + 16 + message2->length, sum.contents, cksumsize);
        krb5_free_checksum_contents(context, &sum);
        sum.contents = 0;
        /* Now that we know we're actually generating the token...  */
        ctx->seq_send++;

        if (toktype == KG_TOK_WRAP_MSG) {
#ifdef CFX_EXERCISE
            rrc = rand() & 0xffff;
            /* If the rotate fails, don't worry about it.  */
            if (gss_krb5int_rotate_left(outbuf+16, bufsize-16,
                            (bufsize-16) - (rrc % (bufsize - 16))))
                store_16_be(rrc, outbuf+6);
#endif
            /* Fix up EC field.  */
            store_16_be(cksumsize, outbuf+4);
        } else {
            store_16_be(0xffff, outbuf+6);
        }
    } else if (toktype == KG_TOK_MIC_MSG) {
        tok_id = KG2_TOK_MIC_MSG;
        message2 = &empty_message;
        goto wrap_with_checksum;
    } else if (toktype == KG_TOK_DEL_CTX) {
        tok_id = KG2_TOK_DEL_CTX;
        message = message2 = &empty_message;
        goto wrap_with_checksum;
    } else
        abort();

    token->value = outbuf;
    token->length = bufsize;
    return 0;

error:
    free(outbuf);
    token->value = NULL;
    token->length = 0;
    return err;
}
Exemple #10
0
int
ksm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
{
    krb5_auth_context auth_context = NULL;
    krb5_error_code retcode;
    krb5_ccache     cc = NULL;
    int             retval = SNMPERR_SUCCESS;
    krb5_data       outdata, ivector;
    krb5_keyblock  *subkey = NULL;
#ifdef MIT_NEW_CRYPTO
    krb5_data       input;
    krb5_enc_data   output;
    unsigned int    numcksumtypes;
    krb5_cksumtype  *cksumtype_array;
#else                           /* MIT_NEW_CRYPTO */
    krb5_encrypt_block eblock;
#endif                          /* MIT_NEW_CRYPTO */
    size_t          blocksize, encrypted_length;
    unsigned char  *encrypted_data = NULL;
    int             zero = 0, i;
    u_char         *cksum_pointer, *endp = *parms->wholeMsg;
    krb5_cksumtype  cksumtype;
    krb5_checksum   pdu_checksum;
    u_char         **wholeMsg = parms->wholeMsg;
    size_t	   *offset = parms->wholeMsgOffset, seq_offset;
    struct ksm_secStateRef *ksm_state = (struct ksm_secStateRef *)
        parms->secStateRef;
    int rc;

    DEBUGMSGTL(("ksm", "Starting KSM processing\n"));

    outdata.length = 0;
    outdata.data = NULL;
    ivector.length = 0;
    ivector.data = NULL;
    pdu_checksum.contents = NULL;

    if (!ksm_state) {
        /*
         * If we don't have a ksm_state, then we're a request.  Get a
         * credential cache and build a ap_req.
         */
        retcode = krb5_cc_default(kcontext, &cc);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_cc_default failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        DEBUGMSGTL(("ksm", "KSM: Set credential cache successfully\n"));

        /*
         * This seems odd, since we don't need this until later (or earlier,
         * depending on how you look at it), but because the most likely
         * errors are Kerberos at this point, I'll get this now to save
         * time not encoding the rest of the packet.
         *
         * Also, we need the subkey to encrypt the PDU (if required).
         */

        retcode =
            krb5_mk_req(kcontext, &auth_context,
                        AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
                        (char *) service_name, parms->session->peername, NULL,
                        cc, &outdata);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_mk_req failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

	DEBUGMSGTL(("ksm", "KSM: ticket retrieved successfully for \"%s/%s\" "
		    "(may not be actual ticket sname)\n", service_name,
		    parms->session->peername));

    } else {

        /*
         * Grab the auth_context from our security state reference
         */

        auth_context = ksm_state->auth_context;

        /*
         * Bundle up an AP_REP.  Note that we do this only when we
         * have a security state reference (which means we're in an agent
         * and we're sending a response).
         */

        DEBUGMSGTL(("ksm", "KSM: Starting reply processing.\n"));

        retcode = krb5_mk_rep(kcontext, auth_context, &outdata);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_mk_rep failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        DEBUGMSGTL(("ksm", "KSM: Finished with krb5_mk_rep()\n"));
    }

    /*
     * If we have to encrypt the PDU, do that now
     */

    if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {

        DEBUGMSGTL(("ksm", "KSM: Starting PDU encryption.\n"));

        /*
         * It's weird -
         *
         * If we're on the manager, it's a local subkey (because that's in
         * our AP_REQ)
         *
         * If we're on the agent, it's a remote subkey (because that comes
         * FROM the received AP_REQ).
         */

        if (ksm_state)
            retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context,
                                                    &subkey);
        else
            retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context,
                                                   &subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm",
                        "KSM: krb5_auth_con_getlocalsubkey failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        /*
         * Note that here we need to handle different things between the
         * old and new crypto APIs.  First, we need to get the final encrypted
         * length of the PDU.
         */

#ifdef MIT_NEW_CRYPTO
        retcode = krb5_c_encrypt_length(kcontext, subkey->enctype,
                                        parms->scopedPduLen,
                                        &encrypted_length);

        if (retcode) {
            DEBUGMSGTL(("ksm",
                        "Encryption length calculation failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#else                           /* MIT_NEW_CRYPTO */

        krb5_use_enctype(kcontext, &eblock, subkey->enctype);
        retcode = krb5_process_key(kcontext, &eblock, subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_process_key failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        encrypted_length = krb5_encrypt_size(parms->scopedPduLen,
                                             eblock.crypto_entry);
#endif                          /* MIT_NEW_CRYPTO */

        encrypted_data = malloc(encrypted_length);

        if (!encrypted_data) {
            DEBUGMSGTL(("ksm",
                        "KSM: Unable to malloc %d bytes for encrypt "
                        "buffer: %s\n", parms->scopedPduLen,
                        strerror(errno)));
            retval = SNMPERR_MALLOC;
#ifndef MIT_NEW_CRYPTO
            krb5_finish_key(kcontext, &eblock);
#endif                          /* ! MIT_NEW_CRYPTO */

            goto error;
        }

        /*
         * We need to set up a blank initialization vector for the encryption.
         * Use a block of all zero's (which is dependent on the block size
         * of the encryption method).
         */

#ifdef MIT_NEW_CRYPTO

        retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize);

        if (retcode) {
            DEBUGMSGTL(("ksm",
                        "Unable to determine crypto block size: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#else                           /* MIT_NEW_CRYPTO */

        blocksize =
            krb5_enctype_array[subkey->enctype]->system->block_length;

#endif                          /* MIT_NEW_CRYPTO */

        ivector.data = malloc(blocksize);

        if (!ivector.data) {
            DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivector\n",
                        blocksize));
            retval = SNMPERR_MALLOC;
            goto error;
        }

        ivector.length = blocksize;
        memset(ivector.data, 0, blocksize);

        /*
         * Finally!  Do the encryption!
         */

#ifdef MIT_NEW_CRYPTO

        input.data = (char *) parms->scopedPdu;
        input.length = parms->scopedPduLen;
        output.ciphertext.data = (char *) encrypted_data;
        output.ciphertext.length = encrypted_length;

        retcode =
            krb5_c_encrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION,
                           &ivector, &input, &output);

#else                           /* MIT_NEW_CRYPTO */

        retcode = krb5_encrypt(kcontext, (krb5_pointer) parms->scopedPdu,
                               (krb5_pointer) encrypted_data,
                               parms->scopedPduLen, &eblock, ivector.data);

        krb5_finish_key(kcontext, &eblock);

#endif                          /* MIT_NEW_CRYPTO */

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_encrypt failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

	*offset = 0;

        rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen,
                                             offset, 1,
                                             (u_char) (ASN_UNIVERSAL |
                                                       ASN_PRIMITIVE |
                                                       ASN_OCTET_STR),
                                             encrypted_data,
                                             encrypted_length);

        if (rc == 0) {
            DEBUGMSGTL(("ksm", "Building encrypted payload failed.\n"));
            retval = SNMPERR_TOO_LONG;
            goto error;
        }

        DEBUGMSGTL(("ksm", "KSM: Encryption complete.\n"));

    } else {
        /*
         * Plaintext PDU (not encrypted)
         */

        if (*parms->wholeMsgLen < parms->scopedPduLen) {
            DEBUGMSGTL(("ksm", "Not enough room for plaintext PDU.\n"));
            retval = SNMPERR_TOO_LONG;
            goto error;
        }
    }

    /*
     * Start encoding the msgSecurityParameters
     *
     * For now, use 0 for the response hint
     */

    DEBUGMSGTL(("ksm", "KSM: scopedPdu added to payload\n"));

    seq_offset = *offset;

    rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen,
                                      offset, 1,
                                      (u_char) (ASN_UNIVERSAL |
                                                ASN_PRIMITIVE |
                                                ASN_INTEGER),
                                      (long *) &zero, sizeof(zero));

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen,
                                         offset, 1,
                                         (u_char) (ASN_UNIVERSAL |
                                                   ASN_PRIMITIVE |
                                                   ASN_OCTET_STR),
                                         (u_char *) outdata.data,
                                         outdata.length);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm AP_REQ failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    /*
     * Now, we need to pick the "right" checksum algorithm.  For old
     * crypto, just pick CKSUMTYPE_RSA_MD5_DES; for new crypto, pick
     * one of the "approved" ones.
     */

#ifdef MIT_NEW_CRYPTO
    retcode = krb5_c_keyed_checksum_types(kcontext, subkey->enctype,
                                          &numcksumtypes, &cksumtype_array);

    if (retcode) {
	DEBUGMSGTL(("ksm", "Unable to find appropriate keyed checksum: %s\n",
		    error_message(retcode)));
	snmp_set_detail(error_message(retcode));
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (numcksumtypes <= 0) {
	DEBUGMSGTL(("ksm", "We received a list of zero cksumtypes for this "
		    "enctype (%d)\n", subkey->enctype));
	snmp_set_detail("No valid checksum type for this encryption type");
	retval = SNMPERR_KRB5;
	goto error;
    }

    /*
     * It's not clear to me from the API which checksum you're supposed
     * to support, so I'm taking a guess at the first one
     */

    cksumtype = cksumtype_array[0];

    krb5_free_cksumtypes(kcontext, cksumtype_array);

    DEBUGMSGTL(("ksm", "KSM: Choosing checksum type of %d (subkey type "
		"of %d)\n", cksumtype, subkey->enctype));

    retcode = krb5_c_checksum_length(kcontext, cksumtype, &blocksize);

    if (retcode) {
        DEBUGMSGTL(("ksm", "Unable to determine checksum length: %s\n",
                    error_message(retcode)));
        snmp_set_detail(error_message(retcode));
        retval = SNMPERR_KRB5;
        goto error;
    }

    pdu_checksum.length = blocksize;

#else /* MIT_NEW_CRYPTO */
    if (ksm_state)
        cksumtype = ksm_state->cksumtype;
    else
	cksumtype = CKSUMTYPE_RSA_MD5_DES;

    if (!is_keyed_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
                    cksumtype));
        snmp_set_detail("Checksum is not a keyed checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (!is_coll_proof_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
                    "checksum\n", cksumtype));
        snmp_set_detail("Checksum is not a collision-proof checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    pdu_checksum.length = krb5_checksum_size(kcontext, cksumtype);
    pdu_checksum.checksum_type = cksumtype;

#endif /* MIT_NEW_CRYPTO */

    /*
     * Note that here, we're just leaving blank space for the checksum;
     * we remember where that is, and we'll fill it in later.
     */

    *offset += pdu_checksum.length;
    memset(*wholeMsg + *parms->wholeMsgLen - *offset, 0, pdu_checksum.length);

    cksum_pointer = *wholeMsg + *parms->wholeMsgLen - *offset;

    rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen,
                                         parms->wholeMsgOffset, 1,
                                         (u_char) (ASN_UNIVERSAL |
                                                   ASN_PRIMITIVE |
                                                   ASN_OCTET_STR),
                                         pdu_checksum.length);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen,
                                      parms->wholeMsgOffset, 1,
                                      (u_char) (ASN_UNIVERSAL |
                                                ASN_PRIMITIVE |
                                                ASN_OCTET_STR),
                                      (long *) &cksumtype,
                                      sizeof(cksumtype));

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen,
                                           parms->wholeMsgOffset, 1,
                                           (u_char) (ASN_SEQUENCE |
                                                     ASN_CONSTRUCTOR),
                                           *offset - seq_offset);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen,
                                         parms->wholeMsgOffset, 1,
                                         (u_char) (ASN_UNIVERSAL |
                                                   ASN_PRIMITIVE |
                                                   ASN_OCTET_STR),
                                         *offset - seq_offset);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    DEBUGMSGTL(("ksm", "KSM: Security parameter encoding completed\n"));

    /*
     * We're done with the KSM security parameters - now we do the global
     * header and wrap up the whole PDU.
     */

    if (*parms->wholeMsgLen < parms->globalDataLen) {
        DEBUGMSGTL(("ksm", "Building global data failed.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    *offset += parms->globalDataLen;
    memcpy(*wholeMsg + *parms->wholeMsgLen - *offset,
	   parms->globalData, parms->globalDataLen);

    rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen,
                                           offset, 1,
                                           (u_char) (ASN_SEQUENCE |
                                                     ASN_CONSTRUCTOR),
                                           *offset);

    if (rc == 0) {
        DEBUGMSGTL(("ksm", "Building master packet sequence.\n"));
        retval = SNMPERR_TOO_LONG;
        goto error;
    }

    DEBUGMSGTL(("ksm", "KSM: PDU master packet encoding complete.\n"));

    /*
     * Now we need to checksum the entire PDU (since it's built).
     */

    pdu_checksum.contents = malloc(pdu_checksum.length);

    if (!pdu_checksum.contents) {
        DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum\n",
                    pdu_checksum.length));
        retval = SNMPERR_MALLOC;
        goto error;
    }

    /*
     * If we didn't encrypt the packet, we haven't yet got the subkey.
     * Get that now.
     */

    if (!subkey) {
        if (ksm_state)
            retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context,
                                                    &subkey);
        else
            retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context,
                                                   &subkey);
        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_auth_con_getlocalsubkey failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
    }
#ifdef MIT_NEW_CRYPTO

    input.data = (char *) (*wholeMsg + *parms->wholeMsgLen - *offset);
    input.length = *offset;
        retcode = krb5_c_make_checksum(kcontext, cksumtype, subkey,
                                       KSM_KEY_USAGE_CHECKSUM, &input,
                                       &pdu_checksum);

#else                           /* MIT_NEW_CRYPTO */

    retcode = krb5_calculate_checksum(kcontext, cksumtype, *wholeMsg +
				      *parms->wholeMsgLen - *offset,
                                      *offset,
                                      (krb5_pointer) subkey->contents,
                                      subkey->length, &pdu_checksum);

#endif                          /* MIT_NEW_CRYPTO */

    if (retcode) {
        DEBUGMSGTL(("ksm", "Calculate checksum failed: %s\n",
                    error_message(retcode)));
        retval = SNMPERR_KRB5;
        snmp_set_detail(error_message(retcode));
        goto error;
    }

    DEBUGMSGTL(("ksm", "KSM: Checksum calculation complete.\n"));

    memcpy(cksum_pointer, pdu_checksum.contents, pdu_checksum.length);

    DEBUGMSGTL(("ksm", "KSM: Writing checksum of %d bytes at offset %d\n",
                pdu_checksum.length, cksum_pointer - (*wholeMsg + 1)));

    DEBUGMSGTL(("ksm", "KSM: Checksum:"));

    for (i = 0; i < pdu_checksum.length; i++)
        DEBUGMSG(("ksm", " %02x",
                  (unsigned int) pdu_checksum.contents[i]));

    DEBUGMSG(("ksm", "\n"));

    /*
     * If we're _not_ called as part of a response (null ksm_state),
     * then save the auth_context for later using our cache routines.
     */

    if (!ksm_state) {
        if ((retval = ksm_insert_cache(parms->pdu->msgid, auth_context,
                                       (u_char *) parms->secName,
                                       parms->secNameLen)) !=
            SNMPERR_SUCCESS)
            goto error;
        auth_context = NULL;
    }

    DEBUGMSGTL(("ksm", "KSM processing complete!\n"));

  error:

    if (pdu_checksum.contents)
#ifdef MIT_NEW_CRYPTO
        krb5_free_checksum_contents(kcontext, &pdu_checksum);
#else                           /* MIT_NEW_CRYPTO */
        free(pdu_checksum.contents);
#endif                          /* MIT_NEW_CRYPTO */

    if (ivector.data)
        free(ivector.data);

    if (subkey)
        krb5_free_keyblock(kcontext, subkey);

    if (encrypted_data)
        free(encrypted_data);

    if (cc)
        krb5_cc_close(kcontext, cc);

    if (auth_context && !ksm_state)
        krb5_auth_con_free(kcontext, auth_context);

    return retval;
}
Exemple #11
0
static krb5_error_code
pkinit_server_verify_padata(krb5_context context,
			    struct _krb5_db_entry_new * client,
			    krb5_data *req_pkt,
			    krb5_kdc_req * request,
			    krb5_enc_tkt_part * enc_tkt_reply,
			    krb5_pa_data * data,
			    preauth_get_entry_data_proc server_get_entry_data,
			    void *pa_plugin_context,
			    void **pa_request_context,
			    krb5_data **e_data,
			    krb5_authdata ***authz_data)
{
    krb5_error_code retval = 0;	
    krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
    krb5_data *encoded_pkinit_authz_data = NULL;
    krb5_pa_pk_as_req *reqp = NULL;
    krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
    krb5_auth_pack *auth_pack = NULL;
    krb5_auth_pack_draft9 *auth_pack9 = NULL;
    pkinit_kdc_context plgctx = NULL;
    pkinit_kdc_req_context reqctx;
    krb5_preauthtype pa_type;
    krb5_checksum cksum = {0, 0, 0, NULL};
    krb5_data *der_req = NULL;
    int valid_eku = 0, valid_san = 0;
    krb5_authdata **my_authz_data = NULL, *pkinit_authz_data = NULL;
    krb5_kdc_req *tmp_as_req = NULL;
    krb5_data k5data;

    pkiDebug("pkinit_verify_padata: entered!\n");
    if (data == NULL || data->length <= 0 || data->contents == NULL)
	return 0;

    if (pa_plugin_context == NULL || e_data == NULL)
	return EINVAL;

    plgctx = pkinit_find_realm_context(context, pa_plugin_context,
				       request->server);
    if (plgctx == NULL)
	return 0;

#ifdef DEBUG_ASN1
    print_buffer_bin(data->contents, data->length, "/tmp/kdc_as_req");
#endif
    /* create a per-request context */
    retval = pkinit_init_kdc_req_context(context, (void **)&reqctx);
    if (retval)
	goto cleanup;
    reqctx->pa_type = data->pa_type;

    PADATA_TO_KRB5DATA(data, &k5data);

    switch ((int)data->pa_type) {
	case KRB5_PADATA_PK_AS_REQ:
	    pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
	    pa_type = (int)data->pa_type;
	    retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
	    if (retval) {
		pkiDebug("decode_krb5_pa_pk_as_req failed\n");
		goto cleanup;
	    }
#ifdef DEBUG_ASN1
	    print_buffer_bin(reqp->signedAuthPack.data,
			     reqp->signedAuthPack.length,
			     "/tmp/kdc_signed_data");
#endif
	    retval = cms_signeddata_verify(context, plgctx->cryptoctx,
		reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_CLIENT,
		plgctx->opts->require_crl_checking,
		reqp->signedAuthPack.data, reqp->signedAuthPack.length,
		&authp_data.data, &authp_data.length, &krb5_authz.data, 
		&krb5_authz.length);
	    break;
	case KRB5_PADATA_PK_AS_REP_OLD:
	case KRB5_PADATA_PK_AS_REQ_OLD:
	    pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
	    pa_type = KRB5_PADATA_PK_AS_REQ_OLD;
	    retval = k5int_decode_krb5_pa_pk_as_req_draft9(&k5data, &reqp9);
	    if (retval) {
		pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed\n");
		goto cleanup;
	    }
#ifdef DEBUG_ASN1
	    print_buffer_bin(reqp9->signedAuthPack.data,
			     reqp9->signedAuthPack.length,
			     "/tmp/kdc_signed_data_draft9");
#endif

	    retval = cms_signeddata_verify(context, plgctx->cryptoctx,
		reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9,
		plgctx->opts->require_crl_checking,
		reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
		&authp_data.data, &authp_data.length, &krb5_authz.data, 
		&krb5_authz.length);
	    break;
	default:
	    pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
	    retval = EINVAL;
	    goto cleanup;
    }
    if (retval) {
	pkiDebug("pkcs7_signeddata_verify failed\n");
	goto cleanup;
    }

    retval = verify_client_san(context, plgctx, reqctx, request->client,
			       &valid_san);
    if (retval)
	goto cleanup;
    if (!valid_san) {
	pkiDebug("%s: did not find an acceptable SAN in user certificate\n",
		 __FUNCTION__);
	retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
	goto cleanup;
    }
    retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
    if (retval)
	goto cleanup;

    if (!valid_eku) {
	pkiDebug("%s: did not find an acceptable EKU in user certificate\n",
		 __FUNCTION__);
	retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
	goto cleanup;
    }

#ifdef DEBUG_ASN1
    print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
#endif

    OCTETDATA_TO_KRB5DATA(&authp_data, &k5data);
    switch ((int)data->pa_type) {
	case KRB5_PADATA_PK_AS_REQ:
	    retval = k5int_decode_krb5_auth_pack(&k5data, &auth_pack);
	    if (retval) {
		pkiDebug("failed to decode krb5_auth_pack\n");
		goto cleanup;
	    }

	    /* check dh parameters */
	    if (auth_pack->clientPublicValue != NULL) {	
		retval = server_check_dh(context, plgctx->cryptoctx,
		    reqctx->cryptoctx, plgctx->idctx,
		    &auth_pack->clientPublicValue->algorithm.parameters,
		    plgctx->opts->dh_min_bits);

		if (retval) {
		    pkiDebug("bad dh parameters\n");
		    goto cleanup;
		}
	    }
	    /*
	     * The KDC may have modified the request after decoding it.
	     * We need to compute the checksum on the data that
	     * came from the client.  Therefore, we use the original
	     * packet contents.
	     */
	    retval = k5int_decode_krb5_as_req(req_pkt, &tmp_as_req); 
	    if (retval) {
		pkiDebug("decode_krb5_as_req returned %d\n", (int)retval);
		goto cleanup;
	    }
		
	    retval = k5int_encode_krb5_kdc_req_body(tmp_as_req, &der_req);
	    if (retval) {
		pkiDebug("encode_krb5_kdc_req_body returned %d\n", (int) retval);
		goto cleanup;
	    }
	    retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL,
					  0, der_req, &cksum);
	    if (retval) {
		pkiDebug("unable to calculate AS REQ checksum\n");
		goto cleanup;
	    }
	    if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
		memcmp(cksum.contents,
		       auth_pack->pkAuthenticator.paChecksum.contents,
		       cksum.length)) {
		pkiDebug("failed to match the checksum\n");
#ifdef DEBUG_CKSUM
		pkiDebug("calculating checksum on buf size (%d)\n",
			 req_pkt->length);
		print_buffer(req_pkt->data, req_pkt->length);
		pkiDebug("received checksum type=%d size=%d ",
			auth_pack->pkAuthenticator.paChecksum.checksum_type,
			auth_pack->pkAuthenticator.paChecksum.length);
		print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
			     auth_pack->pkAuthenticator.paChecksum.length);
		pkiDebug("expected checksum type=%d size=%d ",
			 cksum.checksum_type, cksum.length);
		print_buffer(cksum.contents, cksum.length);
#endif

		retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
		goto cleanup;
	    }

	    /* check if kdcPkId present and match KDC's subjectIdentifier */
	    if (reqp->kdcPkId.data != NULL) {
		int valid_kdcPkId = 0;
		retval = pkinit_check_kdc_pkid(context, plgctx->cryptoctx,
		    reqctx->cryptoctx, plgctx->idctx,
		    reqp->kdcPkId.data, reqp->kdcPkId.length, &valid_kdcPkId);
		if (retval)
		    goto cleanup;
		if (!valid_kdcPkId)
		    pkiDebug("kdcPkId in AS_REQ does not match KDC's cert"
			     "RFC says to ignore and proceed\n");

	    }
	    /* remember the decoded auth_pack for verify_padata routine */
	    reqctx->rcv_auth_pack = auth_pack;
	    auth_pack = NULL;
	    break;
	case KRB5_PADATA_PK_AS_REP_OLD:
	case KRB5_PADATA_PK_AS_REQ_OLD:
	    retval = k5int_decode_krb5_auth_pack_draft9(&k5data, &auth_pack9);
	    if (retval) {
		pkiDebug("failed to decode krb5_auth_pack_draft9\n");
		goto cleanup;
	    }
	    if (auth_pack9->clientPublicValue != NULL) {	
		retval = server_check_dh(context, plgctx->cryptoctx,
		    reqctx->cryptoctx, plgctx->idctx,
		    &auth_pack9->clientPublicValue->algorithm.parameters,
		    plgctx->opts->dh_min_bits);

		if (retval) {
		    pkiDebug("bad dh parameters\n");
		    goto cleanup;
		}
	    }
	    /* remember the decoded auth_pack for verify_padata routine */
	    reqctx->rcv_auth_pack9 = auth_pack9;
	    auth_pack9 = NULL;
	    break;
    }

    /* return authorization data to be included in the ticket */
    switch ((int)data->pa_type) {
	case KRB5_PADATA_PK_AS_REQ:
	    my_authz_data = malloc(2 * sizeof(*my_authz_data));
	    if (my_authz_data == NULL) {
		retval = ENOMEM;
		pkiDebug("Couldn't allocate krb5_authdata ptr array\n");
		goto cleanup;
	    }
	    my_authz_data[1] = NULL;
	    my_authz_data[0] = malloc(sizeof(krb5_authdata));
	    if (my_authz_data[0] == NULL) {
		retval = ENOMEM;
		pkiDebug("Couldn't allocate krb5_authdata\n");
		free(my_authz_data);
		goto cleanup;
	    }
	    /* AD-INITIAL-VERIFIED-CAS must be wrapped in AD-IF-RELEVANT */
	    my_authz_data[0]->magic = KV5M_AUTHDATA;
	    my_authz_data[0]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;

	    /* create an internal AD-INITIAL-VERIFIED-CAS data */
	    pkinit_authz_data = malloc(sizeof(krb5_authdata));
	    if (pkinit_authz_data == NULL) {
		retval = ENOMEM;
		pkiDebug("Couldn't allocate krb5_authdata\n");
		free(my_authz_data[0]);
		free(my_authz_data);
		goto cleanup;
	    }
	    pkinit_authz_data->ad_type = KRB5_AUTHDATA_INITIAL_VERIFIED_CAS;
	    /* content of this ad-type contains the certification
	       path with which the client certificate was validated
	     */
	    pkinit_authz_data->contents = krb5_authz.data;
	    pkinit_authz_data->length = krb5_authz.length;
	    retval = k5int_encode_krb5_authdata_elt(pkinit_authz_data, 
			    &encoded_pkinit_authz_data);
#ifdef DEBUG_ASN1
	    print_buffer_bin((unsigned char *)encoded_pkinit_authz_data->data,
			     encoded_pkinit_authz_data->length,
			     "/tmp/kdc_pkinit_authz_data");
#endif
	    free(pkinit_authz_data);
	    if (retval) {
		pkiDebug("k5int_encode_krb5_authdata_elt failed\n");
		free(my_authz_data[0]);
		free(my_authz_data);
		goto cleanup;
	    }

	    my_authz_data[0]->contents =
			    (krb5_octet *) encoded_pkinit_authz_data->data;
	    my_authz_data[0]->length = encoded_pkinit_authz_data->length;
	    *authz_data = my_authz_data;
	    pkiDebug("Returning %d bytes of authorization data\n", 
		     krb5_authz.length);
	    encoded_pkinit_authz_data->data = NULL; /* Don't free during cleanup*/
	    free(encoded_pkinit_authz_data);
	    break;
	default: 
	    *authz_data = NULL;
    }
    /* remember to set the PREAUTH flag in the reply */
    enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
    *pa_request_context = reqctx;
    reqctx = NULL;

  cleanup:
    if (retval && data->pa_type == KRB5_PADATA_PK_AS_REQ) {
	pkiDebug("pkinit_verify_padata failed: creating e-data\n");
	if (pkinit_create_edata(context, plgctx->cryptoctx, reqctx->cryptoctx,
		plgctx->idctx, plgctx->opts, retval, e_data))
	    pkiDebug("pkinit_create_edata failed\n");
    }

    switch ((int)data->pa_type) {
	case KRB5_PADATA_PK_AS_REQ:
	    free_krb5_pa_pk_as_req(&reqp);
	    if (cksum.contents != NULL)
		free(cksum.contents);
	    if (der_req != NULL)
		 krb5_free_data(context, der_req);
	    break;
	case KRB5_PADATA_PK_AS_REP_OLD:
	case KRB5_PADATA_PK_AS_REQ_OLD:
	    free_krb5_pa_pk_as_req_draft9(&reqp9);
    }
    if (tmp_as_req != NULL)
	k5int_krb5_free_kdc_req(context, tmp_as_req); 
    if (authp_data.data != NULL)
	free(authp_data.data);
    if (krb5_authz.data != NULL)
	free(krb5_authz.data);
    if (reqctx != NULL)
	pkinit_fini_kdc_req_context(context, reqctx);
    if (auth_pack != NULL)
	free_krb5_auth_pack(&auth_pack);
    if (auth_pack9 != NULL)
	free_krb5_auth_pack_draft9(context, &auth_pack9);

    return retval;
}
krb5_error_code KRB5_CALLCONV
krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context,
		     krb5_flags ap_req_options, krb5_data *in_data,
		     krb5_creds *in_creds, krb5_data *outbuf)
{
    krb5_error_code 	  retval;
    krb5_checksum	  checksum;
    krb5_checksum	  *checksump = 0;
    krb5_auth_context	  new_auth_context;
    krb5_enctype	  *desired_etypes = NULL;

    krb5_ap_req request;
    krb5_data *scratch = 0;
    krb5_data *toutbuf;

    request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
    request.authenticator.ciphertext.data = NULL;
    request.ticket = 0;
    
    if (!in_creds->ticket.length) 
	return(KRB5_NO_TKT_SUPPLIED);

    if ((ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) &&
	!(ap_req_options & AP_OPTS_MUTUAL_REQUIRED))
	return(EINVAL);

    /* we need a native ticket */
    if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
	return(retval);
    
    /* verify that the ticket is not expired */
    if ((retval = krb5_validate_times(context, &in_creds->times)) != 0)
	goto cleanup;

    /* generate auth_context if needed */
    if (*auth_context == NULL) {
	if ((retval = krb5_auth_con_init(context, &new_auth_context)))
	    goto cleanup;
	*auth_context = new_auth_context;
    }

    if ((*auth_context)->keyblock != NULL) {
	krb5_free_keyblock(context, (*auth_context)->keyblock);
	(*auth_context)->keyblock = NULL;
    }

    /* set auth context keyblock */
    if ((retval = krb5_copy_keyblock(context, &in_creds->keyblock, 
				     &((*auth_context)->keyblock))))
	goto cleanup;

    /* generate seq number if needed */
    if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
     || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
      && ((*auth_context)->local_seq_number == 0)) 
	if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock,
				     &(*auth_context)->local_seq_number)))
	    goto cleanup;
	

    /* generate subkey if needed */
    if (!in_data &&(*auth_context)->checksum_func) {
	retval = (*auth_context)->checksum_func( context,
						 *auth_context,
						 (*auth_context)->checksum_func_data,
						 &in_data);
	if (retval)
	    goto cleanup;
    }

    if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->send_subkey)) {
	retval = krb5int_generate_and_save_subkey (context, *auth_context,
						   &in_creds->keyblock,
						   in_creds->keyblock.enctype);
	if (retval)
	    goto cleanup;
    }


    if (in_data) {

      if ((*auth_context)->req_cksumtype == 0x8003) {
	    /* XXX Special hack for GSSAPI */
	    checksum.checksum_type = 0x8003;
	    checksum.length = in_data->length;
	    checksum.contents = (krb5_octet *) in_data->data;
	} else {
	    krb5_cksumtype cksumtype;
	    retval = krb5int_c_mandatory_cksumtype(context, (*auth_context)->keyblock->enctype,
						   &cksumtype);
	    if (retval)
		goto cleanup_cksum;
	    if ((*auth_context)->req_cksumtype)
		cksumtype = (*auth_context)->req_cksumtype;
	    if ((retval = krb5_c_make_checksum(context, 
					       cksumtype,
					       (*auth_context)->keyblock,
					       KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
					       in_data, &checksum)))
		goto cleanup_cksum;
	}
	checksump = &checksum;
    }

    /* Generate authenticator */
    if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof(
					krb5_authenticator))) == NULL) {
	retval = ENOMEM;
	goto cleanup_cksum;
    }

    if (ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) {
	if ((*auth_context)->permitted_etypes == NULL) {
	    retval = krb5_get_tgs_ktypes(context, in_creds->server, &desired_etypes);
	    if (retval)
		goto cleanup_cksum;
	} else
	    desired_etypes = (*auth_context)->permitted_etypes;
    }

    if ((retval = krb5_generate_authenticator(context,
					      (*auth_context)->authentp,
					      in_creds->client, checksump,
					      (*auth_context)->send_subkey,
					      (*auth_context)->local_seq_number,
					      in_creds->authdata,
					      (*auth_context)->ad_context,
					      desired_etypes,
					      in_creds->keyblock.enctype)))
	goto cleanup_cksum;
	
    /* encode the authenticator */
    if ((retval = encode_krb5_authenticator((*auth_context)->authentp,
					    &scratch)))
	goto cleanup_cksum;
    
    /* call the encryption routine */
    if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
				      KRB5_KEYUSAGE_AP_REQ_AUTH,
				      scratch, &request.authenticator)))
	goto cleanup_cksum;

    if ((retval = encode_krb5_ap_req(&request, &toutbuf)))
	goto cleanup_cksum;
    *outbuf = *toutbuf;

    free(toutbuf);

cleanup_cksum:
    /* Null out these fields, to prevent pointer sharing problems;
     * they were supplied by the caller
     */
    if ((*auth_context)->authentp != NULL) {
	(*auth_context)->authentp->client = NULL;
	(*auth_context)->authentp->checksum = NULL;
    }
    if (checksump && checksump->checksum_type != 0x8003)
      free(checksump->contents);

cleanup:
    if (desired_etypes &&
	desired_etypes != (*auth_context)->permitted_etypes)
	free(desired_etypes);
    if (request.ticket)
	krb5_free_ticket(context, request.ticket);
    if (request.authenticator.ciphertext.data) {
    	(void) memset(request.authenticator.ciphertext.data, 0,
		      request.authenticator.ciphertext.length);
	free(request.authenticator.ciphertext.data);
    }
    if (scratch) {
	memset(scratch->data, 0, scratch->length);
        free(scratch->data);
	free(scratch);
    }
    return retval;
}
Exemple #13
0
static krb5_error_code
make_seal_token_v1 (krb5_context context,
                    krb5_keyblock *enc,
                    krb5_keyblock *seq,
                    gssint_uint64 *seqnum,
                    int direction,
                    gss_buffer_t text,
                    gss_buffer_t token,
                    int signalg,
                    size_t cksum_size,
                    int sealalg,
                    int do_encrypt,
                    int toktype,
                    int bigend,
                    gss_OID oid)
{
    krb5_error_code code;
    size_t sumlen;
    char *data_ptr;
    krb5_data plaind;
    krb5_checksum md5cksum;
    krb5_checksum cksum;
    /* msglen contains the message length
     * we are signing/encrypting.  tmsglen
     * contains the length of the message
     * we plan to write out to the token.
     * tlen is the length of the token
     * including header. */
    unsigned int conflen=0, tmsglen, tlen, msglen;
    unsigned char *t, *ptr;
    unsigned char *plain;
    unsigned char pad;
    krb5_keyusage sign_usage = KG_USAGE_SIGN;


    assert((!do_encrypt) || (toktype == KG_TOK_SEAL_MSG));
    /* create the token buffer */
    /* Do we need confounder? */
    if (do_encrypt || (!bigend && (toktype == KG_TOK_SEAL_MSG)))
        conflen = kg_confounder_size(context, enc);
    else conflen = 0;

    if (toktype == KG_TOK_SEAL_MSG) {
        switch (sealalg) {
        case SEAL_ALG_MICROSOFT_RC4:
            msglen = conflen + text->length+1;
            pad = 1;
            break;
        default:
            /* XXX knows that des block size is 8 */
            msglen = (conflen+text->length+8)&(~7);
            pad = 8-(text->length%8);
        }
        tmsglen = msglen;
    } else {
        tmsglen = 0;
        msglen = text->length;
        pad = 0;
    }
    tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);

    if ((t = (unsigned char *) xmalloc(tlen)) == NULL)
        return(ENOMEM);

    /*** fill in the token */

    ptr = t;
    g_make_token_header(oid, 14+cksum_size+tmsglen, &ptr, toktype);

    /* 0..1 SIGN_ALG */
    store_16_le(signalg, &ptr[0]);

    /* 2..3 SEAL_ALG or Filler */
    if ((toktype == KG_TOK_SEAL_MSG) && do_encrypt) {
        store_16_le(sealalg, &ptr[2]);
    } else {
        /* No seal */
        ptr[2] = 0xff;
        ptr[3] = 0xff;
    }

    /* 4..5 Filler */
    ptr[4] = 0xff;
    ptr[5] = 0xff;

    /* pad the plaintext, encrypt if needed, and stick it in the token */

    /* initialize the the cksum */
    switch (signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_MD2_5:
        md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
        break;
    case SGN_ALG_HMAC_MD5:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
        if (toktype != KG_TOK_SEAL_MSG)
            sign_usage = 15;
        break;
    default:
    case SGN_ALG_DES_MAC:
        abort ();
    }

    code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
    if (code) {
        xfree(t);
        return(code);
    }
    md5cksum.length = sumlen;


    if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) {
        xfree(t);
        return(ENOMEM);
    }

    if (conflen) {
        if ((code = kg_make_confounder(context, enc, plain))) {
            xfree(plain);
            xfree(t);
            return(code);
        }
    }

    memcpy(plain+conflen, text->value, text->length);
    if (pad) memset(plain+conflen+text->length, pad, pad);

    /* compute the checksum */

    /* 8 = head of token body as specified by mech spec */
    if (! (data_ptr =
           (char *) xmalloc(8 + (bigend ? text->length : msglen)))) {
        xfree(plain);
        xfree(t);
        return(ENOMEM);
    }
    (void) memcpy(data_ptr, ptr-2, 8);
    if (bigend)
        (void) memcpy(data_ptr+8, text->value, text->length);
    else
        (void) memcpy(data_ptr+8, plain, msglen);
    plaind.length = 8 + (bigend ? text->length : msglen);
    plaind.data = data_ptr;
    code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq,
                                sign_usage, &plaind, &md5cksum);
    xfree(data_ptr);

    if (code) {
        xfree(plain);
        xfree(t);
        return(code);
    }
    switch(signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case 3:

        if ((code = kg_encrypt(context, seq, KG_USAGE_SEAL,
                               (g_OID_equal(oid, gss_mech_krb5_old) ?
                                seq->contents : NULL),
                               md5cksum.contents, md5cksum.contents, 16))) {
            krb5_free_checksum_contents(context, &md5cksum);
            xfree (plain);
            xfree(t);
            return code;
        }

        cksum.length = cksum_size;
        cksum.contents = md5cksum.contents + 16 - cksum.length;

        memcpy(ptr+14, cksum.contents, cksum.length);
        break;

    case SGN_ALG_HMAC_SHA1_DES3_KD:
        /*
         * Using key derivation, the call to krb5_c_make_checksum
         * already dealt with encrypting.
         */
        if (md5cksum.length != cksum_size)
            abort ();
        memcpy (ptr+14, md5cksum.contents, md5cksum.length);
        break;
    case SGN_ALG_HMAC_MD5:
        memcpy (ptr+14, md5cksum.contents, cksum_size);
        break;
    }

    krb5_free_checksum_contents(context, &md5cksum);

    /* create the seq_num */

    if ((code = kg_make_seq_num(context, seq, direction?0:0xff,
                                (krb5_ui_4)*seqnum, ptr+14, ptr+6))) {
        xfree (plain);
        xfree(t);
        return(code);
    }

    if (do_encrypt) {
        switch(sealalg) {
        case SEAL_ALG_MICROSOFT_RC4:
        {
            unsigned char bigend_seqnum[4];
            krb5_keyblock *enc_key;
            int i;
            store_32_be(*seqnum, bigend_seqnum);
            code = krb5_copy_keyblock (context, enc, &enc_key);
            if (code)
            {
                xfree(plain);
                xfree(t);
                return(code);
            }
            assert (enc_key->length == 16);
            for (i = 0; i <= 15; i++)
                ((char *) enc_key->contents)[i] ^=0xf0;
            code = kg_arcfour_docrypt (enc_key, 0,
                                       bigend_seqnum, 4,
                                       plain, tmsglen,
                                       ptr+14+cksum_size);
            krb5_free_keyblock (context, enc_key);
            if (code)
            {
                xfree(plain);
                xfree(t);
                return(code);
            }
        }
        break;
        default:
            if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL,
                                   (krb5_pointer) plain,
                                   (krb5_pointer) (ptr+cksum_size+14),
                                   tmsglen))) {
                xfree(plain);
                xfree(t);
                return(code);
            }
        }
    }else {
        if (tmsglen)
            memcpy(ptr+14+cksum_size, plain, tmsglen);
    }
    xfree(plain);


    /* that's it.  return the token */

    (*seqnum)++;
    *seqnum &= 0xffffffffL;

    token->length = tlen;
    token->value = (void *) t;

    return(0);
}
Exemple #14
0
/*
 * Create a CAMMAC for contents, using enc_tkt and the first key from krbtgt
 * for the KDC verifier.  Set *cammac_out to a single-element authdata list
 * containing the CAMMAC inside an IF-RELEVANT container.
 */
krb5_error_code
cammac_create(krb5_context context, krb5_enc_tkt_part *enc_tkt,
              krb5_keyblock *server_key, krb5_db_entry *krbtgt,
              krb5_authdata **contents, krb5_authdata ***cammac_out)
{
    krb5_error_code ret;
    krb5_data *der_authdata = NULL, *der_enctkt = NULL, *der_cammac = NULL;
    krb5_authdata ad, *list[2];
    krb5_cammac cammac;
    krb5_verifier_mac kdc_verifier, svc_verifier;
    krb5_key_data *kd;
    krb5_keyblock tgtkey;
    krb5_checksum kdc_cksum, svc_cksum;

    *cammac_out = NULL;
    memset(&tgtkey, 0, sizeof(tgtkey));
    memset(&kdc_cksum, 0, sizeof(kdc_cksum));
    memset(&svc_cksum, 0, sizeof(svc_cksum));

    /* Fetch the first krbtgt key for the KDC verifier. */
    ret = krb5_dbe_find_enctype(context, krbtgt, -1, -1, 0, &kd);
    if (ret)
        goto cleanup;
    ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL);
    if (ret)
        goto cleanup;

    /* Checksum the reply with contents as authdata for the KDC verifier. */
    ret = encode_kdcver_encpart(enc_tkt, contents, &der_enctkt);
    if (ret)
        goto cleanup;
    ret = krb5_c_make_checksum(context, 0, &tgtkey, KRB5_KEYUSAGE_CAMMAC,
                               der_enctkt, &kdc_cksum);
    if (ret)
        goto cleanup;
    kdc_verifier.princ = NULL;
    kdc_verifier.kvno = kd->key_data_kvno;
    kdc_verifier.enctype = ENCTYPE_NULL;
    kdc_verifier.checksum = kdc_cksum;

    /* Encode the authdata and checksum it for the service verifier. */
    ret = encode_krb5_authdata(contents, &der_authdata);
    if (ret)
        goto cleanup;
    ret = krb5_c_make_checksum(context, 0, server_key, KRB5_KEYUSAGE_CAMMAC,
                               der_authdata, &svc_cksum);
    if (ret)
        goto cleanup;
    svc_verifier.princ = NULL;
    svc_verifier.kvno = 0;
    svc_verifier.enctype = ENCTYPE_NULL;
    svc_verifier.checksum = svc_cksum;

    cammac.elements = contents;
    cammac.kdc_verifier = &kdc_verifier;
    cammac.svc_verifier = &svc_verifier;
    cammac.other_verifiers = NULL;

    ret = encode_krb5_cammac(&cammac, &der_cammac);
    if (ret)
        goto cleanup;

    /* Wrap the encoded CAMMAC in an IF-RELEVANT container and return it as a
     * single-element authdata list. */
    ad.ad_type = KRB5_AUTHDATA_CAMMAC;
    ad.length = der_cammac->length;
    ad.contents = (uint8_t *)der_cammac->data;
    list[0] = &ad;
    list[1] = NULL;
    ret = krb5_encode_authdata_container(context, KRB5_AUTHDATA_IF_RELEVANT,
                                         list, cammac_out);

cleanup:
    krb5_free_data(context, der_enctkt);
    krb5_free_data(context, der_authdata);
    krb5_free_data(context, der_cammac);
    krb5_free_keyblock_contents(context, &tgtkey);
    krb5_free_checksum_contents(context, &kdc_cksum);
    krb5_free_checksum_contents(context, &svc_cksum);
    return ret;
}
Exemple #15
0
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context = NULL;
    size_t i;
    struct test *test;
    krb5_keyblock kb, *kbp;
    krb5_checksum cksum;
    krb5_cksumtype mtype;
    krb5_boolean valid, verbose = FALSE;
    int status = 0;

    if (argc >= 2 && strcmp(argv[1], "-v") == 0)
        verbose = TRUE;
    for (i = 0; i < sizeof(test_cases) / sizeof(*test_cases); i++) {
        test = &test_cases[i];
        if (test->enctype != 0) {
            kb.magic = KV5M_KEYBLOCK;
            kb.enctype = test->enctype;
            kb.length = test->keybits.length;
            kb.contents = (unsigned char *)test->keybits.data;
            kbp = &kb;
        } else
            kbp = NULL;
        ret = krb5_c_make_checksum(context, test->sumtype, kbp, test->usage,
                                   &test->plaintext, &cksum);
        assert(!ret);
        if (verbose) {
            char buf[64];
            krb5_cksumtype_to_string(test->sumtype, buf, sizeof(buf));
            printf("\nTest %d:\n", (int)i);
            printf("Plaintext: %.*s\n", (int)test->plaintext.length,
                   test->plaintext.data);
            printf("Checksum type: %s\n", buf);
            if (test->enctype != 0) {
                krb5_enctype_to_name(test->enctype, FALSE, buf, sizeof(buf));
                printf("Enctype: %s\n", buf);
                printhex("Key: ", test->keybits.data, test->keybits.length);
                printf("Key usage: %d\n", (int)test->usage);
            }
            printhex("Checksum: ", cksum.contents, cksum.length);
        }
        if (test->cksum.length != cksum.length ||
            memcmp(test->cksum.data, cksum.contents, cksum.length) != 0) {
            printf("derive test %d failed\n", (int)i);
            status = 1;
            if (!verbose)
                break;
        }

        /* Test that the checksum verifies successfully. */
        ret = krb5_c_verify_checksum(context, kbp, test->usage,
                                     &test->plaintext, &cksum, &valid);
        assert(!ret);
        if (!valid) {
            printf("test %d verify failed\n", (int)i);
            status = 1;
            if (!verbose)
                break;
        }

        if (kbp != NULL) {
            ret = krb5int_c_mandatory_cksumtype(context, kbp->enctype, &mtype);
            assert(!ret);
            if (test->sumtype == mtype) {
                /* Test that a checksum type of 0 uses the mandatory checksum
                 * type for the key. */
                cksum.checksum_type = 0;
                ret = krb5_c_verify_checksum(context, kbp, test->usage,
                                             &test->plaintext, &cksum, &valid);
                assert(!ret && valid);
            }
        }

        krb5_free_checksum_contents(context, &cksum);
    }
    return status;
}
static krb5_error_code
pkinit_server_verify_padata(krb5_context context,
                            struct _krb5_db_entry_new * client,
                            krb5_data *req_pkt,
                            krb5_kdc_req * request,
                            krb5_enc_tkt_part * enc_tkt_reply,
                            krb5_pa_data * data,
                            preauth_get_entry_data_proc server_get_entry_data,
                            void *pa_plugin_context,
                            void **pa_request_context,
                            krb5_data **e_data,
                            krb5_authdata ***authz_data)
{
    krb5_error_code retval = 0;
    krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
    krb5_pa_pk_as_req *reqp = NULL;
    krb5_pa_pk_as_req_draft9 *reqp9 = NULL;
    krb5_auth_pack *auth_pack = NULL;
    krb5_auth_pack_draft9 *auth_pack9 = NULL;
    pkinit_kdc_context plgctx = NULL;
    pkinit_kdc_req_context reqctx;
    krb5_preauthtype pa_type;
    krb5_checksum cksum = {0, 0, 0, NULL};
    krb5_data *der_req = NULL;
    int valid_eku = 0, valid_san = 0;
    krb5_kdc_req *tmp_as_req = NULL;
    krb5_data k5data;
    int is_signed = 1;
    krb5_keyblock *armor_key;

    pkiDebug("pkinit_verify_padata: entered!\n");
    if (data == NULL || data->length <= 0 || data->contents == NULL)
        return 0;

    /* Remove (along with armor_key) when FAST PKINIT is settled. */
    retval = fast_kdc_get_armor_key(context, server_get_entry_data, request,
                                    client, &armor_key);
    if (retval == 0 && armor_key != NULL) {
        /* Don't allow PKINIT if the client used FAST. */
        krb5_free_keyblock(context, armor_key);
        return EINVAL;
    }

    if (pa_plugin_context == NULL || e_data == NULL)
        return EINVAL;

    plgctx = pkinit_find_realm_context(context, pa_plugin_context,
                                       request->server);
    if (plgctx == NULL)
        return 0;

#ifdef DEBUG_ASN1
    print_buffer_bin(data->contents, data->length, "/tmp/kdc_as_req");
#endif
    /* create a per-request context */
    retval = pkinit_init_kdc_req_context(context, (void **)&reqctx);
    if (retval)
        goto cleanup;
    reqctx->pa_type = data->pa_type;

    PADATA_TO_KRB5DATA(data, &k5data);

    switch ((int)data->pa_type) {
    case KRB5_PADATA_PK_AS_REQ:
        pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
        pa_type = (int)data->pa_type;
        retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp);
        if (retval) {
            pkiDebug("decode_krb5_pa_pk_as_req failed\n");
            goto cleanup;
        }
#ifdef DEBUG_ASN1
        print_buffer_bin(reqp->signedAuthPack.data,
                         reqp->signedAuthPack.length,
                         "/tmp/kdc_signed_data");
#endif
        retval = cms_signeddata_verify(context, plgctx->cryptoctx,
                                       reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_CLIENT,
                                       plgctx->opts->require_crl_checking,
                                       reqp->signedAuthPack.data, reqp->signedAuthPack.length,
                                       &authp_data.data, &authp_data.length, &krb5_authz.data,
                                       &krb5_authz.length, &is_signed);
        break;
    case KRB5_PADATA_PK_AS_REP_OLD:
    case KRB5_PADATA_PK_AS_REQ_OLD:
        pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n");
        pa_type = KRB5_PADATA_PK_AS_REQ_OLD;
        retval = k5int_decode_krb5_pa_pk_as_req_draft9(&k5data, &reqp9);
        if (retval) {
            pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed\n");
            goto cleanup;
        }
#ifdef DEBUG_ASN1
        print_buffer_bin(reqp9->signedAuthPack.data,
                         reqp9->signedAuthPack.length,
                         "/tmp/kdc_signed_data_draft9");
#endif

        retval = cms_signeddata_verify(context, plgctx->cryptoctx,
                                       reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9,
                                       plgctx->opts->require_crl_checking,
                                       reqp9->signedAuthPack.data, reqp9->signedAuthPack.length,
                                       &authp_data.data, &authp_data.length, &krb5_authz.data,
                                       &krb5_authz.length, NULL);
        break;
    default:
        pkiDebug("unrecognized pa_type = %d\n", data->pa_type);
        retval = EINVAL;
        goto cleanup;
    }
    if (retval) {
        pkiDebug("pkcs7_signeddata_verify failed\n");
        goto cleanup;
    }
    if (is_signed) {

        retval = verify_client_san(context, plgctx, reqctx, request->client,
                                   &valid_san);
        if (retval)
            goto cleanup;
        if (!valid_san) {
            pkiDebug("%s: did not find an acceptable SAN in user "
                     "certificate\n", __FUNCTION__);
            retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
            goto cleanup;
        }
        retval = verify_client_eku(context, plgctx, reqctx, &valid_eku);
        if (retval)
            goto cleanup;

        if (!valid_eku) {
            pkiDebug("%s: did not find an acceptable EKU in user "
                     "certificate\n", __FUNCTION__);
            retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE;
            goto cleanup;
        }
    } else { /* !is_signed */
        if (!krb5_principal_compare(context, request->client,
                                    krb5_anonymous_principal())) {
            retval = KRB5KDC_ERR_PREAUTH_FAILED;
            krb5_set_error_message(context, retval, "Pkinit request not "
                                   "signed, but client not anonymous.");
            goto cleanup;
        }
    }
#ifdef DEBUG_ASN1
    print_buffer_bin(authp_data.data, authp_data.length, "/tmp/kdc_auth_pack");
#endif

    OCTETDATA_TO_KRB5DATA(&authp_data, &k5data);
    switch ((int)data->pa_type) {
    case KRB5_PADATA_PK_AS_REQ:
        retval = k5int_decode_krb5_auth_pack(&k5data, &auth_pack);
        if (retval) {
            pkiDebug("failed to decode krb5_auth_pack\n");
            goto cleanup;
        }

        /* check dh parameters */
        if (auth_pack->clientPublicValue != NULL) {
            retval = server_check_dh(context, plgctx->cryptoctx,
                                     reqctx->cryptoctx, plgctx->idctx,
                                     &auth_pack->clientPublicValue->algorithm.parameters,
                                     plgctx->opts->dh_min_bits);

            if (retval) {
                pkiDebug("bad dh parameters\n");
                goto cleanup;
            }
        } else if (!is_signed) {
            /*Anonymous pkinit requires DH*/
            retval = KRB5KDC_ERR_PREAUTH_FAILED;
            krb5_set_error_message(context, retval, "Anonymous pkinit without DH public value not supported.");
            goto cleanup;
        }
        /*
         * The KDC may have modified the request after decoding it.
         * We need to compute the checksum on the data that
         * came from the client.  Therefore, we use the original
         * packet contents.
         */
        retval = k5int_decode_krb5_as_req(req_pkt, &tmp_as_req);
        if (retval) {
            pkiDebug("decode_krb5_as_req returned %d\n", (int)retval);
            goto cleanup;
        }

        retval = k5int_encode_krb5_kdc_req_body(tmp_as_req, &der_req);
        if (retval) {
            pkiDebug("encode_krb5_kdc_req_body returned %d\n", (int) retval);
            goto cleanup;
        }
        retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL,
                                      0, der_req, &cksum);
        if (retval) {
            pkiDebug("unable to calculate AS REQ checksum\n");
            goto cleanup;
        }
        if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
            memcmp(cksum.contents,
                   auth_pack->pkAuthenticator.paChecksum.contents,
                   cksum.length)) {
            pkiDebug("failed to match the checksum\n");
#ifdef DEBUG_CKSUM
            pkiDebug("calculating checksum on buf size (%d)\n",
                     req_pkt->length);
            print_buffer(req_pkt->data, req_pkt->length);
            pkiDebug("received checksum type=%d size=%d ",
                     auth_pack->pkAuthenticator.paChecksum.checksum_type,
                     auth_pack->pkAuthenticator.paChecksum.length);
            print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
                         auth_pack->pkAuthenticator.paChecksum.length);
            pkiDebug("expected checksum type=%d size=%d ",
                     cksum.checksum_type, cksum.length);
            print_buffer(cksum.contents, cksum.length);
#endif

            retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
            goto cleanup;
        }

        /* check if kdcPkId present and match KDC's subjectIdentifier */
        if (reqp->kdcPkId.data != NULL) {
            int valid_kdcPkId = 0;
            retval = pkinit_check_kdc_pkid(context, plgctx->cryptoctx,
                                           reqctx->cryptoctx, plgctx->idctx,
                                           reqp->kdcPkId.data, reqp->kdcPkId.length, &valid_kdcPkId);
            if (retval)
                goto cleanup;
            if (!valid_kdcPkId)
                pkiDebug("kdcPkId in AS_REQ does not match KDC's cert"
                         "RFC says to ignore and proceed\n");

        }
        /* remember the decoded auth_pack for verify_padata routine */
        reqctx->rcv_auth_pack = auth_pack;
        auth_pack = NULL;
        break;
    case KRB5_PADATA_PK_AS_REP_OLD:
    case KRB5_PADATA_PK_AS_REQ_OLD:
        retval = k5int_decode_krb5_auth_pack_draft9(&k5data, &auth_pack9);
        if (retval) {
            pkiDebug("failed to decode krb5_auth_pack_draft9\n");
            goto cleanup;
        }
        if (auth_pack9->clientPublicValue != NULL) {
            retval = server_check_dh(context, plgctx->cryptoctx,
                                     reqctx->cryptoctx, plgctx->idctx,
                                     &auth_pack9->clientPublicValue->algorithm.parameters,
                                     plgctx->opts->dh_min_bits);

            if (retval) {
                pkiDebug("bad dh parameters\n");
                goto cleanup;
            }
        }
        /* remember the decoded auth_pack for verify_padata routine */
        reqctx->rcv_auth_pack9 = auth_pack9;
        auth_pack9 = NULL;
        break;
    }

    /*
     * This code used to generate ad-initial-verified-cas authorization data.
     * However that has been removed until the ad-kdc-issued discussion can
     * happen in the working group.  Dec 2009
     */
    /* return authorization data to be included in the ticket */
    switch ((int)data->pa_type) {
    default:
        *authz_data = NULL;
    }
    /* remember to set the PREAUTH flag in the reply */
    enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
    *pa_request_context = reqctx;
    reqctx = NULL;

cleanup:
    if (retval && data->pa_type == KRB5_PADATA_PK_AS_REQ) {
        pkiDebug("pkinit_verify_padata failed: creating e-data\n");
        if (pkinit_create_edata(context, plgctx->cryptoctx, reqctx->cryptoctx,
                                plgctx->idctx, plgctx->opts, retval, e_data))
            pkiDebug("pkinit_create_edata failed\n");
    }

    switch ((int)data->pa_type) {
    case KRB5_PADATA_PK_AS_REQ:
        free_krb5_pa_pk_as_req(&reqp);
        free(cksum.contents);
        if (der_req != NULL)
            krb5_free_data(context, der_req);
        break;
    case KRB5_PADATA_PK_AS_REP_OLD:
    case KRB5_PADATA_PK_AS_REQ_OLD:
        free_krb5_pa_pk_as_req_draft9(&reqp9);
    }
    if (tmp_as_req != NULL)
        k5int_krb5_free_kdc_req(context, tmp_as_req);
    free(authp_data.data);
    free(krb5_authz.data);
    if (reqctx != NULL)
        pkinit_fini_kdc_req_context(context, reqctx);
    if (auth_pack != NULL)
        free_krb5_auth_pack(&auth_pack);
    if (auth_pack9 != NULL)
        free_krb5_auth_pack_draft9(context, &auth_pack9);

    return retval;
}
Exemple #17
0
krb5_error_code
krb5int_fast_prep_req(krb5_context context,
                      struct krb5int_fast_request_state *state,
                      krb5_kdc_req *request,
                      const krb5_data *to_be_checksummed,
                      kdc_req_encoder_proc encoder,
                      krb5_data **encoded_request)
{
    krb5_error_code retval = 0;
    krb5_pa_data *pa_array[2], **pa_tgs_array = NULL;
    krb5_pa_data pa[2];
    krb5_fast_req fast_req;
    krb5_pa_data *tgs = NULL;
    krb5_fast_armored_req *armored_req = NULL;
    krb5_data *encoded_fast_req = NULL;
    krb5_data *encoded_armored_req = NULL;
    krb5_data *local_encoded_result = NULL;
    int i, j;

    assert(state != NULL);
    assert(state->fast_outer_request.padata == NULL);
    memset(pa_array, 0, sizeof(pa_array));
    if (state->armor_key == NULL) {
        return encoder(request, encoded_request);
    }

    TRACE_FAST_ENCODE(context);
    state->nonce = request->nonce;
    fast_req.req_body = request;
    if (fast_req.req_body->padata == NULL) {
        fast_req.req_body->padata = calloc(1, sizeof(krb5_pa_data *));
        if (fast_req.req_body->padata == NULL)
            retval = ENOMEM;
    }
    fast_req.fast_options = state->fast_options;
    if (retval == 0
        && (tgs = krb5int_find_pa_data(context, fast_req.req_body->padata,
                                       KRB5_PADATA_AP_REQ)) != NULL) {
        krb5_pa_data **paptr = &fast_req.req_body->padata[0];
        for (i = 0, j = 0; paptr[j] != NULL; j++) {
            if (paptr[j]->pa_type == KRB5_PADATA_AP_REQ)
                paptr[j] = NULL;
            else
                paptr[i++] = paptr[j];
        }
        paptr[i] = NULL;
    }
    if (retval == 0)
        retval = encode_krb5_fast_req(&fast_req, &encoded_fast_req);
    if (retval == 0) {
        armored_req = calloc(1, sizeof(krb5_fast_armored_req));
        if (armored_req == NULL)
            retval = ENOMEM;
    }
    if (retval == 0)
        armored_req->armor = state->armor;
    if (retval ==0)
        retval = krb5_c_make_checksum(context, 0, state->armor_key,
                                      KRB5_KEYUSAGE_FAST_REQ_CHKSUM,
                                      to_be_checksummed,
                                      &armored_req->req_checksum);
    if (retval == 0)
        retval = krb5_encrypt_helper(context, state->armor_key,
                                     KRB5_KEYUSAGE_FAST_ENC, encoded_fast_req,
                                     &armored_req->enc_part);
    if (retval == 0)
        retval = encode_krb5_pa_fx_fast_request(armored_req,
                                                &encoded_armored_req);
    if (retval == 0) {
        pa[0].pa_type = KRB5_PADATA_FX_FAST;
        pa[0].contents = (unsigned char *) encoded_armored_req->data;
        pa[0].length = encoded_armored_req->length;
        if (tgs) {
            retval = make_tgs_outer_padata(tgs, pa, request->padata,
                                           &pa_tgs_array);
            state->fast_outer_request.padata = pa_tgs_array;
        } else {
            pa_array[0] = &pa[0];
            state->fast_outer_request.padata = pa_array;
        }
    }
    if (retval == 0)
        retval = encoder(&state->fast_outer_request, &local_encoded_result);
    if (retval == 0) {
        *encoded_request = local_encoded_result;
        local_encoded_result = NULL;
    }
    if (encoded_armored_req)
        krb5_free_data(context, encoded_armored_req);
    if (armored_req) {
        armored_req->armor = NULL; /*owned by state*/
        krb5_free_fast_armored_req(context, armored_req);
    }
    if (encoded_fast_req)
        krb5_free_data(context, encoded_fast_req);
    if (local_encoded_result)
        krb5_free_data(context, local_encoded_result);
    if (tgs) {
        free(tgs->contents);
        free(tgs);
    }
    state->fast_outer_request.padata = NULL;
    free(pa_tgs_array);
    return retval;
}
Exemple #18
0
static krb5_error_code
client_process(krb5_context kcontext,
	       void *client_plugin_context,
	       void *client_request_context,
	       krb5_get_init_creds_opt *opt,
	       preauth_get_client_data_proc client_get_data_proc,
	       struct _krb5_preauth_client_rock *rock,
	       krb5_kdc_req *request,
	       krb5_data *encoded_request_body,
	       krb5_data *encoded_previous_request,
	       krb5_pa_data *pa_data,
	       krb5_prompter_fct prompter,
	       void *prompter_data,
	       preauth_get_as_key_proc gak_fct,
	       void *gak_data,
	       krb5_data *salt, krb5_data *s2kparams,
	       krb5_keyblock *as_key,
	       krb5_pa_data **out_pa_data)
{
    krb5_pa_data *send_pa;
    krb5_checksum checksum;
    krb5_enctype enctype;
    krb5_cksumtype *cksumtypes;
    krb5_error_code status = 0;
    krb5_int32 cksumtype, *enctypes;
    unsigned int i, n_enctypes, cksumtype_count;
    int num_gic_info = 0;
    krb5_gic_opt_pa_data *gic_info;

    status = krb5_get_init_creds_opt_get_pa(kcontext, opt,
					    &num_gic_info, &gic_info);
    if (status && status != ENOENT) {
#ifdef DEBUG
	fprintf(stderr, "Error from krb5_get_init_creds_opt_get_pa: %s\n",
		error_message(status));
#endif
	return status;
    }
#ifdef DEBUG
    fprintf(stderr, "(cksum_body) Got the following gic options:\n");
#endif
    for (i = 0; i < num_gic_info; i++) {
#ifdef DEBUG
	fprintf(stderr, "  '%s' = '%s'\n", gic_info[i].attr, gic_info[i].value);
#endif
    }
    krb5_get_init_creds_opt_free_pa(kcontext, num_gic_info, gic_info);

    memset(&checksum, 0, sizeof(checksum));

    /* Get the user's long-term key if we haven't asked for it yet.  Try
     * all of the encryption types which the server supports. */
    if (as_key->length == 0) {
	if ((pa_data != NULL) && (pa_data->length >= 4)) {
#ifdef DEBUG
	    fprintf(stderr, "%d bytes of preauth data.\n", pa_data->length);
#endif
	    n_enctypes = pa_data->length / 4;
	    enctypes = (krb5_int32*) pa_data->contents;
	} else {
	    n_enctypes = request->nktypes;
	}
	for (i = 0; i < n_enctypes; i++) {
	    if ((pa_data != NULL) && (pa_data->length >= 4)) {
		memcpy(&enctype, pa_data->contents + 4 * i, 4);
		enctype = ntohl(enctype);
	    } else {
		enctype = request->ktype[i];
	    }
#ifdef DEBUG
	    fprintf(stderr, "Asking for AS key (type = %d).\n", enctype);
#endif
	    status = (*gak_fct)(kcontext, request->client, enctype,
				prompter, prompter_data,
				salt, s2kparams, as_key, gak_data);
	    if (status == 0)
		break;
	}
	if (status != 0)
	    return status;
    }
#ifdef DEBUG
    fprintf(stderr, "Got AS key (type = %d).\n", as_key->enctype);
#endif

    /* Determine an appropriate checksum type for this key. */
    cksumtype_count = 0;
    cksumtypes = NULL;
    status = krb5_c_keyed_checksum_types(kcontext, as_key->enctype,
					 &cksumtype_count, &cksumtypes);
    if (status != 0)
	return status;

    /* Generate the checksum. */
    for (i = 0; i < cksumtype_count; i++) {
	status = krb5_c_make_checksum(kcontext, cksumtypes[i], as_key,
				      KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
				      encoded_request_body,
				      &checksum);
	if (status == 0) {
#ifdef DEBUG
	    fprintf(stderr, "Made checksum (type = %d, %d bytes).\n",
		    checksum.checksum_type, encoded_request_body->length);
#endif
	    break;
	}
    }
    cksumtype = htonl(cksumtypes[i]);
    krb5_free_cksumtypes(kcontext, cksumtypes);
    if (status != 0) {
	if (checksum.length > 0)
	    krb5_free_checksum_contents(kcontext, &checksum);
	return status;
    }

    /* Allocate the preauth data structure. */
    send_pa = malloc(sizeof(krb5_pa_data));
    if (send_pa == NULL) {
	krb5_free_checksum_contents(kcontext, &checksum);
	return ENOMEM;
    }
    send_pa->pa_type = KRB5_PADATA_CKSUM_BODY_REQ;
    send_pa->length = 4 + checksum.length;
    send_pa->contents = malloc(4 + checksum.length);
    if (send_pa->contents == NULL) {
	krb5_free_checksum_contents(kcontext, &checksum);
	free(send_pa);
	return ENOMEM;
    }

    /* Store the checksum. */
    memcpy(send_pa->contents, &cksumtype, 4);
    memcpy(send_pa->contents + 4, checksum.contents, checksum.length);
    *out_pa_data = send_pa;

    /* Clean up. */
    krb5_free_checksum_contents(kcontext, &checksum);

    return 0;
}
Exemple #19
0
krb5_error_code
gss_krb5int_make_seal_token_v3 (krb5_context context,
				krb5_gss_ctx_id_rec *ctx,
				const gss_buffer_desc * message,
				gss_buffer_t token,
				int conf_req_flag, int toktype)
{
    size_t bufsize = 16;
    unsigned char *outbuf = 0;
    krb5_error_code err;
    int key_usage;
    unsigned char acceptor_flag;
    const gss_buffer_desc *message2 = message;
#ifdef CFX_EXERCISE
    size_t rrc;
#endif
    size_t ec;
    unsigned short tok_id;
    krb5_checksum sum;
    krb5_keyblock *key;

    ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
    ASSERT(ctx->big_endian == 0);

    acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
    key_usage = (toktype == KG_TOK_WRAP_MSG
		 ? (ctx->initiate
		    ? KG_USAGE_INITIATOR_SEAL
		    : KG_USAGE_ACCEPTOR_SEAL)
		 : (ctx->initiate
		    ? KG_USAGE_INITIATOR_SIGN
		    : KG_USAGE_ACCEPTOR_SIGN));
    if (ctx->have_acceptor_subkey) {
	key = ctx->acceptor_subkey;
    } else {
	key = ctx->enc;
    }

#ifdef _KERNEL
    context->kef_cipher_mt = get_cipher_mech_type(context, key);
    context->kef_hash_mt = get_hash_mech_type(context, key);

    if ((err = init_key_kef(context->kef_cipher_mt, key))) {
	return (GSS_S_FAILURE);
    }

#endif /* _KERNEL */

#ifdef CFX_EXERCISE
    {
	static int initialized = 0;
	if (!initialized) {
	    srand(time(0));
	    initialized = 1;
	}
    }
#endif

    if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
	krb5_data plain;
	krb5_enc_data cipher;
	size_t ec_max;
	size_t tlen;

	/* 300: Adds some slop.  */
	if (SIZE_MAX - 300 < message->length)
	    return ENOMEM;
	ec_max = SIZE_MAX - message->length - 300;
	if (ec_max > 0xffff)
	    ec_max = 0xffff;
	/*
	 * EC should really be a multiple (1) of the number of octets that
	 * the cryptosystem would pad by if we didn't have the filler.
	 *
	 * For AES-CTS this will always be 0 and we expect no further
	 * enctypes, so there should be no issue here.
	 */
	ec = 0;
	plain.length = message->length + 16 + ec;
	plain.data = MALLOC(plain.length);
	if (plain.data == NULL)
	    return ENOMEM;

	/* Get size of ciphertext.  */
	if ((err = krb5_c_encrypt_length(context,
		ctx->enc->enctype, plain.length, &tlen))) {
	    FREE(plain.data, plain.length);
	    return (err);
        }
	
	bufsize = 16 + tlen;
	/* Allocate space for header plus encrypted data.  */
	outbuf = MALLOC(bufsize);
	if (outbuf == NULL) {
	    FREE(plain.data, plain.length);
	    return ENOMEM;
	}

	/* TOK_ID */
	store_16_be(0x0504, outbuf);
	/* flags */
	outbuf[2] = (acceptor_flag
		     | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
		     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
	/* filler */
	outbuf[3] = 0xff;
	/* EC */
	store_16_be(ec, outbuf+4);
	/* RRC */
	store_16_be(0, outbuf+6);
	store_64_be(ctx->seq_send, outbuf+8);

	(void) memcpy(plain.data, message->value, message->length);
	(void) memset(plain.data + message->length, 'x', ec);
	(void) memcpy(plain.data + message->length + ec, outbuf, 16);

	/* Should really use scatter/gather crypto interfaces */
	cipher.ciphertext.data = (char *)outbuf + 16;
	cipher.ciphertext.length = bufsize - 16;
	cipher.enctype = key->enctype;
	err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher);
	(void) bzero(plain.data, plain.length);
	FREE(plain.data, plain.length);
	plain.data = 0;
	if (err)
	    goto error;

	/* Now that we know we're returning a valid token....  */
	ctx->seq_send++;

#ifdef CFX_EXERCISE
	rrc = rand() & 0xffff;
	if (rotate_left(outbuf+16, bufsize-16,
			(bufsize-16) - (rrc % (bufsize - 16))))
	    store_16_be(rrc, outbuf+6);
	/* If the rotate fails, don't worry about it.  */
#endif
    } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
	krb5_data plain;

	/* Here, message is the application-supplied data; message2 is
	   what goes into the output token.  They may be the same, or
	   message2 may be empty (for MIC).  */

	tok_id = 0x0504;

    wrap_with_checksum:
	plain.length = message->length + 16;
	plain.data = MALLOC(message->length + 16);
	if (plain.data == NULL)
	    return ENOMEM;

	if (ctx->cksum_size > 0xffff) {
	    FREE(plain.data, plain.length);
	    return EINVAL;
	}

	bufsize = 16 + message2->length + ctx->cksum_size;
	outbuf = MALLOC(bufsize);
	if (outbuf == NULL) {
	    FREE(plain.data, plain.length);
	    plain.data = 0;
	    err = ENOMEM;
	    goto error;
	}

	/* TOK_ID */
	store_16_be(tok_id, outbuf);
	/* flags */
	outbuf[2] = (acceptor_flag
		     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
	/* filler */
	outbuf[3] = 0xff;
	if (toktype == KG_TOK_WRAP_MSG) {
	    /* Use 0 for checksum calculation, substitute
	       checksum length later.  */
	    /* EC */
	    store_16_be(0, outbuf+4);
	    /* RRC */
	    store_16_be(0, outbuf+6);
	} else {
	    /* MIC and DEL store 0xFF in EC and RRC.  */
	    store_16_be(0xffff, outbuf+4);
	    store_16_be(0xffff, outbuf+6);
	}
	store_64_be(ctx->seq_send, outbuf+8);

	(void) memcpy(plain.data, message->value, message->length);
	(void) memcpy(plain.data + message->length, outbuf, 16);

	/* Fill in the output token -- data contents, if any, and
	   space for the checksum.  */
	if (message2->length)
	    (void) memcpy(outbuf + 16, message2->value, message2->length);

	sum.contents = outbuf + 16 + message2->length;
	sum.length = ctx->cksum_size;

	err = krb5_c_make_checksum(context, ctx->cksumtype, key,
				   key_usage, &plain, &sum);
	bzero(plain.data, plain.length);
	FREE(plain.data, plain.length);
	plain.data = 0;
	if (err) {
	    bzero(outbuf,bufsize);
	    err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
	    goto error;
	}
	if (sum.length != ctx->cksum_size) {
	    err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
	    goto error;
	}
	(void) memcpy(outbuf + 16 + message2->length, sum.contents,
	    ctx->cksum_size);
	krb5_free_checksum_contents(context, &sum);
	sum.contents = 0;
	/* Now that we know we're actually generating the token...  */
	ctx->seq_send++;

	if (toktype == KG_TOK_WRAP_MSG) {
#ifdef CFX_EXERCISE
	    rrc = rand() & 0xffff;
	    /* If the rotate fails, don't worry about it.  */
	    if (rotate_left(outbuf+16, bufsize-16,
			    (bufsize-16) - (rrc % (bufsize - 16))))
		store_16_be(rrc, outbuf+6);
#endif
	    /* Fix up EC field.  */
	    store_16_be(ctx->cksum_size, outbuf+4);
	} else {
	    store_16_be(0xffff, outbuf+6);
	}
    } else if (toktype == KG_TOK_MIC_MSG) {
	tok_id = 0x0404;
	message2 = &empty_message;
	goto wrap_with_checksum;
    } else if (toktype == KG_TOK_DEL_CTX) {
	/*
	 * Solaris Kerberos:
	 * No token should be generated for context deletion. Just
	 * return.
	 */
	return 0;
    } else {
	err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
	goto error;
    }

    token->value = outbuf;
    token->length = bufsize;
    return 0;

error:
    FREE(outbuf, bufsize);
    token->value = NULL;
    token->length = 0;
    return err;
}
Exemple #20
0
/*
 Sends a request to the TGS and waits for a response.
 options is used for the options in the KRB_TGS_REQ.
 timestruct values are used for from, till, rtime " " "
 enctype is used for enctype " " ", and to encrypt the authorization data, 
 sname is used for sname " " "
 addrs, if non-NULL, is used for addresses " " "
 authorization_dat, if non-NULL, is used for authorization_dat " " "
 second_ticket, if required by options, is used for the 2nd ticket in the req.
 in_cred is used for the ticket & session key in the KRB_AP_REQ header " " "
 (the KDC realm is extracted from in_cred->server's realm)
 
 The response is placed into *rep.
 rep->response.data is set to point at allocated storage which should be
 freed by the caller when finished.

 returns system errors
 */
static krb5_error_code 
krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cred, krb5_data *outbuf)
{   
    krb5_error_code       retval;
    krb5_checksum         checksum;
    krb5_authenticator 	  authent;
    krb5_ap_req 	  request;
    krb5_data		* scratch;
    krb5_data           * toutbuf;

    /* Generate checksum */
    if ((retval = krb5_c_make_checksum(context, context->kdc_req_sumtype,
				       &in_cred->keyblock,
				       KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
				       in_data, &checksum))) {
	free(checksum.contents);
	return(retval);
    }

    /* gen authenticator */
    authent.subkey = 0;
    authent.seq_number = 0;
    authent.checksum = &checksum;
    authent.client = in_cred->client;
    authent.authorization_data = in_cred->authdata;
    if ((retval = krb5_us_timeofday(context, &authent.ctime,
				    &authent.cusec))) {
        free(checksum.contents);
	return(retval);
    }

    /* encode the authenticator */
    if ((retval = encode_krb5_authenticator(&authent, &scratch))) {
        free(checksum.contents);
	return(retval);
    }

    free(checksum.contents);

    request.authenticator.ciphertext.data = 0;
    request.authenticator.kvno = 0;
    request.ap_options = 0;
    request.ticket = 0;

    if ((retval = decode_krb5_ticket(&(in_cred)->ticket, &request.ticket)))
	/* Cleanup scratch and scratch data */
        goto cleanup_data;

    /* call the encryption routine */ 
    if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
				      KRB5_KEYUSAGE_TGS_REQ_AUTH,
				      scratch, &request.authenticator)))
	goto cleanup_ticket;

    retval = encode_krb5_ap_req(&request, &toutbuf);
    /* Solaris Kerberos */
    if (retval == 0) {
	*outbuf = *toutbuf;
	krb5_xfree(toutbuf);
    }


    memset(request.authenticator.ciphertext.data, 0,
           request.authenticator.ciphertext.length);
    free(request.authenticator.ciphertext.data);

cleanup_ticket:
    krb5_free_ticket(context, request.ticket);

cleanup_data:
    memset(scratch->data, 0, scratch->length);
    free(scratch->data);

    free(scratch);

    return retval;
}
Exemple #21
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;
}
Exemple #22
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;
}