Beispiel #1
0
krb5_error_code
krb5int_generate_and_save_subkey(krb5_context context,
                                 krb5_auth_context auth_context,
                                 krb5_keyblock *keyblock,
                                 krb5_enctype enctype)
{
    /* Provide some more fodder for random number code.
       This isn't strong cryptographically; the point here is not
       to guarantee randomness, but to make it less likely that multiple
       sessions could pick the same subkey.  */
    struct {
        krb5_int32 sec, usec;
    } rnd_data;
    krb5_data d;
    krb5_error_code retval;
    krb5_keyblock *kb = NULL;

    if (krb5_crypto_us_timeofday(&rnd_data.sec, &rnd_data.usec) == 0) {
        d.length = sizeof(rnd_data);
        d.data = (char *) &rnd_data;
        krb5_c_random_add_entropy(context, KRB5_C_RANDSOURCE_TIMING, &d);
    }

    retval = krb5_generate_subkey_extended(context, keyblock, enctype, &kb);
    if (retval)
        return retval;
    retval = krb5_auth_con_setsendsubkey(context, auth_context, kb);
    if (retval)
        goto cleanup;
    retval = krb5_auth_con_setrecvsubkey(context, auth_context, kb);
    if (retval)
        goto cleanup;

cleanup:
    if (retval) {
        (void) krb5_auth_con_setsendsubkey(context, auth_context, NULL);
        (void) krb5_auth_con_setrecvsubkey(context, auth_context, NULL);
    }
    krb5_free_keyblock(context, kb);
    return retval;
}
Beispiel #2
0
krb5_error_code KRB5_CALLCONV
krb5_rd_rep(krb5_context context, krb5_auth_context auth_context,
            const krb5_data *inbuf, krb5_ap_rep_enc_part **repl)
{
    krb5_error_code       retval;
    krb5_ap_rep          *reply = NULL;
    krb5_ap_rep_enc_part *enc = NULL;
    krb5_data             scratch;

    *repl = NULL;

    if (!krb5_is_ap_rep(inbuf))
        return KRB5KRB_AP_ERR_MSG_TYPE;

    /* Decode inbuf. */
    retval = decode_krb5_ap_rep(inbuf, &reply);
    if (retval)
        return retval;

    /* Put together an eblock for this encryption. */
    scratch.length = reply->enc_part.ciphertext.length;
    scratch.data = malloc(scratch.length);
    if (scratch.data == NULL) {
        retval = ENOMEM;
        goto clean_scratch;
    }

    retval = krb5_k_decrypt(context, auth_context->key,
                            KRB5_KEYUSAGE_AP_REP_ENCPART, 0,
                            &reply->enc_part, &scratch);
    if (retval)
        goto clean_scratch;

    /* Now decode the decrypted stuff. */
    retval = decode_krb5_ap_rep_enc_part(&scratch, &enc);
    if (retval)
        goto clean_scratch;

    /* Check reply fields. */
    if ((enc->ctime != auth_context->authentp->ctime)
        || (enc->cusec != auth_context->authentp->cusec)) {
        retval = KRB5_MUTUAL_FAILED;
        goto clean_scratch;
    }

    /* Set auth subkey. */
    if (enc->subkey) {
        retval = krb5_auth_con_setrecvsubkey(context, auth_context,
                                             enc->subkey);
        if (retval)
            goto clean_scratch;
        retval = krb5_auth_con_setsendsubkey(context, auth_context,
                                             enc->subkey);
        if (retval) {
            (void) krb5_auth_con_setrecvsubkey(context, auth_context, NULL);
            goto clean_scratch;
        }
        /* Not used for anything yet. */
        auth_context->negotiated_etype = enc->subkey->enctype;
    }

    /* Get remote sequence number. */
    auth_context->remote_seq_number = enc->seq_number;

    TRACE_RD_REP(context, enc->ctime, enc->cusec, enc->subkey,
                 enc->seq_number);

    *repl = enc;
    enc = NULL;

clean_scratch:
    if (scratch.data)
        memset(scratch.data, 0, scratch.length);
    free(scratch.data);
    krb5_free_ap_rep(context, reply);
    krb5_free_ap_rep_enc_part(context, enc);
    return retval;
}
Beispiel #3
0
krb5_error_code 
krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data)
{
    char *ptr;
    int plen, vno;
    krb5_data ap_rep;
    krb5_ap_rep_enc_part *ap_rep_enc;
    krb5_error_code ret;
    krb5_data cipherresult;
    krb5_data clearresult;
    krb5_error *krberror;
    krb5_replay_data replay;
    krb5_keyblock *tmp;

    if (packet->length < 4)
	/* either this, or the server is printing bad messages,
	   or the caller passed in garbage */
	return(KRB5KRB_AP_ERR_MODIFIED);

    ptr = packet->data;

    /* verify length */

    plen = (*ptr++ & 0xff);
    plen = (plen<<8) | (*ptr++ & 0xff);

    if (plen != packet->length) 
	{
		/*
		 * MS KDCs *may* send back a KRB_ERROR.  Although
		 * not 100% correct via RFC3244, it's something
		 * we can workaround here.
		 */
		if (krb5_is_krb_error(packet)) {

			if ((ret = krb5_rd_error(context, packet, &krberror)))
			return(ret);

			if (krberror->e_data.data  == NULL) {
				ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
				krb5_free_error(context, krberror);
				return (ret);
			}
		}
		else
		{
			return(KRB5KRB_AP_ERR_MODIFIED);
		}
	}
	

    /* verify version number */

    vno = (*ptr++ & 0xff);
    vno = (vno<<8) | (*ptr++ & 0xff);

    if (vno != 1)
	return(KRB5KDC_ERR_BAD_PVNO);

    /* read, check ap-rep length */

    ap_rep.length = (*ptr++ & 0xff);
    ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff);

    if (ptr + ap_rep.length >= packet->data + packet->length)
	return(KRB5KRB_AP_ERR_MODIFIED);

    if (ap_rep.length) {
	/* verify ap_rep */
	ap_rep.data = ptr;
	ptr += ap_rep.length;

	/*
	 * Save send_subkey to later smash recv_subkey.
	 */
	ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmp);
	if (ret)
	    return ret;

	ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
	if (ret) {
	    krb5_free_keyblock(context, tmp);
	    return(ret);
	}

	krb5_free_ap_rep_enc_part(context, ap_rep_enc);

	/* extract and decrypt the result */

	cipherresult.data = ptr;
	cipherresult.length = (packet->data + packet->length) - ptr;

	/*
	 * Smash recv_subkey to be send_subkey, per spec.
	 */
	ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmp);
	krb5_free_keyblock(context, tmp);
	if (ret)
	    return ret;

	ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
			   &replay);

	if (ret)
	    return(ret);
    } else {
	cipherresult.data = ptr;
	cipherresult.length = (packet->data + packet->length) - ptr;

	if ((ret = krb5_rd_error(context, &cipherresult, &krberror)))
	    return(ret);

	clearresult = krberror->e_data;
    }

    if (clearresult.length < 2) {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }

    ptr = clearresult.data;

    *result_code = (*ptr++ & 0xff);
    *result_code = (*result_code<<8) | (*ptr++ & 0xff);

    if ((*result_code < KRB5_KPASSWD_SUCCESS) ||
	(*result_code > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)) {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }

    /* all success replies should be authenticated/encrypted */

    if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS)) {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }

    result_data->length = (clearresult.data + clearresult.length) - ptr;

    if (result_data->length) {
	result_data->data = (char *) malloc(result_data->length);
	if (result_data->data == NULL) {
	    ret = ENOMEM;
	    goto cleanup;
	}
	memcpy(result_data->data, ptr, result_data->length);
    } else {
	result_data->data = NULL;
    }

    ret = 0;

cleanup:
    if (ap_rep.length) {
	krb5_xfree(clearresult.data);
    } else {
	krb5_free_error(context, krberror);
    }

    return(ret);
}
Beispiel #4
0
krb5_error_code 
krb5int_rd_setpw_rep( krb5_context context, krb5_auth_context auth_context, krb5_data *packet,
     int *result_code, krb5_data *result_data )
{
    char *ptr;
    unsigned int message_length, version_number;
    krb5_data ap_rep;
    krb5_ap_rep_enc_part *ap_rep_enc;
    krb5_error_code ret;
    krb5_data cipherresult;
    krb5_data clearresult;
    krb5_keyblock *tmpkey;
/*
** validate the packet length -
*/
    if (packet->length < 4)
	return(KRB5KRB_AP_ERR_MODIFIED);

    ptr = packet->data;

/*
** see if it is an error
*/
    if (krb5_is_krb_error(packet)) {
	krb5_error *krberror;
	if ((ret = krb5_rd_error(context, packet, &krberror)))
	    return(ret);
	if (krberror->e_data.data  == NULL) {
	    ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
	    krb5_free_error(context, krberror);
	    return (ret);
	}
	clearresult = krberror->e_data;
	krberror->e_data.data  = NULL; /*So we can free it later*/
	krberror->e_data.length = 0;
	krb5_free_error(context, krberror);
		
    } else { /* Not an error*/

/*
** validate the message length -
** length is big endian 
*/
	message_length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
	ptr += 2;
/*
** make sure the message length and packet length agree -
*/
	if (message_length != packet->length)
	    return(KRB5KRB_AP_ERR_MODIFIED);
/*
** get the version number -
*/
	version_number = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
	ptr += 2;
/*
** make sure we support the version returned -
*/
/*
** set password version is 0xff80, change password version is 1
*/
	if (version_number != 1 && version_number != 0xff80)
	    return(KRB5KDC_ERR_BAD_PVNO);
/*
** now fill in ap_rep with the reply -
*/
/*
** get the reply length -
*/
	ap_rep.length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
	ptr += 2;
/*
** validate ap_rep length agrees with the packet length -
*/
	if (ptr + ap_rep.length >= packet->data + packet->length)
	    return(KRB5KRB_AP_ERR_MODIFIED);
/*
** if data was returned, set the ap_rep ptr -
*/
	if( ap_rep.length ) {
	    ap_rep.data = ptr;
	    ptr += ap_rep.length;

	    /*
	     * Save send_subkey to later smash recv_subkey.
	     */
	    ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmpkey);
	    if (ret)
		return ret;

	    ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
	    if (ret) {
		krb5_free_keyblock(context, tmpkey);
		return(ret);
	    }

	    krb5_free_ap_rep_enc_part(context, ap_rep_enc);
/*
** now decrypt the result -
*/
	    cipherresult.data = ptr;
	    cipherresult.length = (packet->data + packet->length) - ptr;

	    /*
	     * Smash recv_subkey to be send_subkey, per spec.
	     */
	    ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmpkey);
	    krb5_free_keyblock(context, tmpkey);
	    if (ret)
		return ret;

	    ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
			       NULL);
	    if (ret)
		return(ret);
	} /*We got an ap_rep*/
	else
	    return (KRB5KRB_AP_ERR_MODIFIED);
    } /*Response instead of error*/

/*
** validate the cleartext length 
*/
    if (clearresult.length < 2) {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }
/*
** now decode the result -
*/
    ptr = clearresult.data;

    *result_code = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
    ptr += 2;

/*
** result code 5 is access denied
*/
    if ((*result_code < KRB5_KPASSWD_SUCCESS) || (*result_code > 5))
    {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }
/*
** all success replies should be authenticated/encrypted
*/
    if( (ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS) )
    {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }

    if (result_data) {
	result_data->length = (clearresult.data + clearresult.length) - ptr;

	if (result_data->length)
	{
	    result_data->data = (char *) malloc(result_data->length);
	    if (result_data->data)
		memcpy(result_data->data, ptr, result_data->length);
	}
	else
	    result_data->data = NULL;
    }
    ret = 0;

 cleanup:
    krb5_free_data_contents(context, &clearresult);
    return(ret);
}