Exemple #1
0
krb5_error_code
krb5_encrypt_tkt_part(krb5_context context,
		      const krb5_keyblock *key,
		      krb5_ticket *ticket)
{
    krb5_data *data = 0;
    int code;
    size_t enclen;

    if ((code = encode_krb5_enc_tkt_part(ticket->enc_part2, &data)))
	goto Done;
    if ((code = krb5_c_encrypt_length(context, key->enctype,
				      data->length, &enclen)))
	goto Done;
    ticket->enc_part.ciphertext.length = enclen;
    if (!(ticket->enc_part.ciphertext.data = malloc(enclen))) {
	code = ENOMEM;
	goto Done;
    }
    if ((code = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_KDC_REP_TICKET,
			       0, data, &ticket->enc_part))) {
	free(ticket->enc_part.ciphertext.data);
	ticket->enc_part.ciphertext.data = 0;
    }
Done:
    if (data) {
	if (data->data)
	    free(data->data);
	free(data);
    }
    return code;
}
krb5_error_code KRB5_CALLCONV
krb5_encrypt(krb5_context context, krb5_const_pointer inptr,
	     krb5_pointer outptr, size_t size, krb5_encrypt_block *eblock,
	     krb5_pointer ivec)
{
    krb5_data inputd, ivecd;
    krb5_enc_data outputd;
    size_t blocksize, outlen;
    krb5_error_code ret;

    if (ivec) {
	if ((ret = krb5_c_block_size(context, eblock->key->enctype, &blocksize)))
	    return(ret);

	ivecd.length = blocksize;
	ivecd.data = ivec;
    }

    /* size is the length of the input cleartext data */
    inputd.length = size;
    inputd.data = inptr;

    /* The size of the output buffer isn't part of the old api.  Not too
       safe.  So, we assume here that it's big enough. */
    if ((ret = krb5_c_encrypt_length(context, eblock->key->enctype, size,
				     &outlen)))
	return(ret);

    outputd.ciphertext.length = outlen;
    outputd.ciphertext.data = outptr;

    return(krb5_c_encrypt(context, eblock->key, 0, ivec?&ivecd:0,
			  &inputd, &outputd));
}
krb5_error_code krb5_encrypt_data(krb5_context context, krb5_keyblock *key,
				  krb5_pointer ivec, krb5_data *data,
				  krb5_enc_data *enc_data)
{
    krb5_error_code ret;
    size_t enclen, blocksize;
    krb5_data ivecd;

    if ((ret = krb5_c_encrypt_length(context, key->enctype, data->length,
				     &enclen)))
	return(ret);

    if (ivec) {
	if ((ret = krb5_c_block_size(context, key->enctype, &blocksize)))
	    return(ret);

	ivecd.length = blocksize;
	ivecd.data = ivec;
    }

    enc_data->magic = KV5M_ENC_DATA;
    enc_data->kvno = 0;
    enc_data->enctype = key->enctype;
    enc_data->ciphertext.length = enclen;
    if ((enc_data->ciphertext.data = malloc(enclen)) == NULL)
	return(ENOMEM);

    if ((ret = krb5_c_encrypt(context, key, 0, ivec?&ivecd:0, data, enc_data)))
	free(enc_data->ciphertext.data);

    return(ret);
}
Exemple #4
0
static int gp_encrypt_buffer(krb5_context context, krb5_keyblock *key,
                             size_t len, void *buf, octet_string *out)
{
    int ret;
    krb5_data data_in;
    krb5_enc_data enc_handle;

    data_in.length = len;
    data_in.data = buf;

    memset(&enc_handle, '\0', sizeof(krb5_enc_data));

    ret = krb5_c_encrypt_length(context,
                                GP_CREDS_HANDLE_KEY_ENCTYPE,
                                data_in.length,
                                (size_t *)&enc_handle.ciphertext.length);
    if (ret) {
        goto done;
    }

    enc_handle.ciphertext.data = malloc(enc_handle.ciphertext.length);
    if (!enc_handle.ciphertext.data) {
        ret = ENOMEM;
        goto done;
    }

    ret = krb5_c_encrypt(context,
                         key,
                         KRB5_KEYUSAGE_APP_DATA_ENCRYPT,
                         NULL,
                         &data_in,
                         &enc_handle);
    if (ret) {
        ret = EINVAL;
        goto done;
    }

    ret = gp_conv_octet_string(enc_handle.ciphertext.length,
                               enc_handle.ciphertext.data,
                               out);
    if (ret) {
        goto done;
    }

done:
    free(enc_handle.ciphertext.data);
    return ret;
}
Exemple #5
0
static krb5_error_code
securid_encrypt_track_data_2(krb5_context context, krb5_db_entry *client,
                             krb5_data *track_data, krb5_data *output)
{
    krb5_error_code retval;
    size_t olen;
    krb5_keyblock sam_key;
    krb5_enc_data tmp_enc_data;

    output->data = NULL;

    retval = get_securid_key(context,client, &sam_key);
    if (retval != 0)
        return retval;

    retval = krb5_c_encrypt_length(context, sam_key.enctype,
                                   track_data->length, &olen);
    if (retval  != 0)
        goto cleanup;
    assert(olen <= 65536);
    output->length = olen;
    output->data = k5alloc(output->length, &retval);
    if (retval)
        goto cleanup;
    tmp_enc_data.ciphertext = *output;
    tmp_enc_data.enctype = sam_key.enctype;
    tmp_enc_data.kvno = 0;

    retval = krb5_c_encrypt(context, &sam_key,
                            KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID, 0,
                            track_data, &tmp_enc_data);
cleanup:
    krb5_free_keyblock_contents(context, &sam_key);

    if (retval) {
        output->length = 0;
        free(output->data);
        output->data = NULL;
        return retval;
    }
    return 0;
}
Exemple #6
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 #7
0
/*
 * Generate a krb5_key_data set by encrypting keys according to
 * enctype/salttype preferences
 */
krb5_error_code ipa_krb5_generate_key_data(krb5_context krbctx,
                                           krb5_principal principal,
                                           krb5_data pwd, int kvno,
                                           krb5_keyblock *kmkey,
                                           int num_encsalts,
                                           krb5_key_salt_tuple *encsalts,
                                           int *_num_keys,
                                           krb5_key_data **_keys)
{
    krb5_error_code kerr;
    krb5_key_data *keys;
    int num_keys;
    int i;

    num_keys = num_encsalts;
    keys = calloc(num_keys, sizeof(krb5_key_data));
    if (!keys) {
        return ENOMEM;
    }

    for (i = 0; i < num_keys; i++) {
        krb5_keyblock key;
        krb5_data salt;
        krb5_octet *ptr;
        krb5_data plain;
        krb5_enc_data cipher;
        krb5_int16 t;
        size_t len;

        salt.data = NULL;

        keys[i].key_data_ver = 2; /* we always have a salt */
        keys[i].key_data_kvno = kvno;

        switch (encsalts[i].ks_salttype) {

        case KRB5_KDB_SALTTYPE_ONLYREALM:

            if (!principal->realm.data) {
                kerr = EINVAL;
                goto done;
            }
            salt.length = principal->realm.length;
            salt.data = malloc(salt.length);
            if (!salt.data) {
                kerr = ENOMEM;
                goto done;
            }
            memcpy(salt.data, principal->realm.data, salt.length);
            break;

        case KRB5_KDB_SALTTYPE_NOREALM:

            kerr = ipa_krb5_principal2salt_norealm(krbctx, principal, &salt);
            if (kerr) {
                goto done;
            }
            break;

        case KRB5_KDB_SALTTYPE_NORMAL:

            kerr = krb5_principal2salt(krbctx, principal, &salt);
            if (kerr) {
                goto done;
            }
            break;

        case KRB5_KDB_SALTTYPE_SPECIAL:

            kerr = ipa_get_random_salt(krbctx, &salt);
            if (kerr) {
                goto done;
            }
            break;

        case KRB5_KDB_SALTTYPE_V4:
            salt.length = 0;
            break;

        case KRB5_KDB_SALTTYPE_AFS3:

            if (!principal->realm.data) {
                kerr = EINVAL;
                goto done;
            }
            salt.data = strndup((char *)principal->realm.data,
                                        principal->realm.length);
            if (!salt.data) {
                kerr = ENOMEM;
                goto done;
            }
            salt.length = SALT_TYPE_AFS_LENGTH; /* special value */
            break;

        default:
            kerr = EINVAL;
            goto done;
        }

        /* need to build the key now to manage the AFS salt.length
         * special case */
        kerr = krb5_c_string_to_key(krbctx,
                                    encsalts[i].ks_enctype,
                                    &pwd, &salt, &key);
        if (kerr) {
            krb5_free_data_contents(krbctx, &salt);
            goto done;
        }
        if (salt.length == SALT_TYPE_AFS_LENGTH) {
            salt.length = strlen(salt.data);
        }

        kerr = krb5_c_encrypt_length(krbctx,
                                     kmkey->enctype, key.length, &len);
        if (kerr) {
            krb5int_c_free_keyblock_contents(krbctx, &key);
            krb5_free_data_contents(krbctx, &salt);
            goto done;
        }

        if ((ptr = (krb5_octet *) malloc(2 + len)) == NULL) {
            kerr = ENOMEM;
            krb5int_c_free_keyblock_contents(krbctx, &key);
            krb5_free_data_contents(krbctx, &salt);
            goto done;
        }

        t = htole16(key.length);
        memcpy(ptr, &t, 2);

        plain.length = key.length;
        plain.data = (char *)key.contents;

        cipher.ciphertext.length = len;
        cipher.ciphertext.data = (char *)ptr+2;

        kerr = krb5_c_encrypt(krbctx, kmkey, 0, 0, &plain, &cipher);
        if (kerr) {
            krb5int_c_free_keyblock_contents(krbctx, &key);
            krb5_free_data_contents(krbctx, &salt);
            free(ptr);
            goto done;
        }

        /* KrbSalt  */
        keys[i].key_data_type[1] = encsalts[i].ks_salttype;

        if (salt.length) {
            keys[i].key_data_length[1] = salt.length;
            keys[i].key_data_contents[1] = (krb5_octet *)salt.data;
        }

        /* EncryptionKey */
        keys[i].key_data_type[0] = key.enctype;
        keys[i].key_data_length[0] = len + 2;
        keys[i].key_data_contents[0] = malloc(len + 2);
        if (!keys[i].key_data_contents[0]) {
            kerr = ENOMEM;
            krb5int_c_free_keyblock_contents(krbctx, &key);
            free(ptr);
            goto done;
        }
        memcpy(keys[i].key_data_contents[0], ptr, len + 2);

        /* make sure we free the memory used now that we are done with it */
        krb5int_c_free_keyblock_contents(krbctx, &key);
        free(ptr);
    }

    *_num_keys = num_keys;
    *_keys = keys;
    kerr = 0;

done:
    if (kerr) {
        ipa_krb5_free_key_data(keys, num_keys);
    }

    return kerr;
}
Exemple #8
0
static krb5_error_code
sam2_process(krb5_context context, krb5_clpreauth_moddata moddata,
	     krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
	     krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
	     krb5_kdc_req *request, krb5_data *encoded_request_body,
	     krb5_data *encoded_previous_request, krb5_pa_data *padata,
	     krb5_prompter_fct prompter, void *prompter_data,
	     krb5_pa_data ***out_padata)
{
    krb5_error_code retval;
    krb5_sam_challenge_2 *sc2 = NULL;
    krb5_sam_challenge_2_body *sc2b = NULL;
    krb5_data tmp_data;
    krb5_data response_data;
    char name[100], banner[100], prompt[100], response[100];
    krb5_prompt kprompt;
    krb5_prompt_type prompt_type;
    krb5_data defsalt, *salt;
    krb5_checksum **cksum;
    krb5_data *scratch = NULL;
    krb5_boolean valid_cksum = 0;
    krb5_enc_sam_response_enc_2 enc_sam_response_enc_2;
    krb5_sam_response_2 sr2;
    size_t ciph_len;
    krb5_pa_data **sam_padata;

    if (prompter == NULL)
        return KRB5_LIBOS_CANTREADPWD;

    tmp_data.length = padata->length;
    tmp_data.data = (char *)padata->contents;

    if ((retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2)))
        return(retval);

    retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b);

    if (retval) {
        krb5_free_sam_challenge_2(context, sc2);
        return(retval);
    }

    if (!sc2->sam_cksum || ! *sc2->sam_cksum) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        return(KRB5_SAM_NO_CHECKSUM);
    }

    if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        return(KRB5_SAM_UNSUPPORTED);
    }

    if (!krb5_c_valid_enctype(sc2b->sam_etype)) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        return(KRB5_SAM_INVALID_ETYPE);
    }

    /* All of the above error checks are KDC-specific, that is, they     */
    /* assume a failure in the KDC reply.  By returning anything other   */
    /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED,               */
    /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will   */
    /* most likely go on to try the AS_REQ against master KDC            */

    if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
        /* We will need the password to obtain the key used for */
        /* the checksum, and encryption of the sam_response.    */
        /* Go ahead and get it now, preserving the ordering of  */
        /* prompts for the user.                                */

        retval = (*rock->gak_fct)(context, request->client, sc2b->sam_etype,
				  prompter, prompter_data, rock->salt,
				  rock->s2kparams, rock->as_key,
				  *rock->gak_data);
        if (retval) {
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            return(retval);
        }
    }

    snprintf(name, sizeof(name), "%.*s",
             SAMDATA(sc2b->sam_type_name, _("SAM Authentication"),
                     sizeof(name) - 1));

    snprintf(banner, sizeof(banner), "%.*s",
             SAMDATA(sc2b->sam_challenge_label,
                     sam_challenge_banner(sc2b->sam_type),
                     sizeof(banner)-1));

    snprintf(prompt, sizeof(prompt), "%s%.*s%s%.*s",
             sc2b->sam_challenge.length?"Challenge is [":"",
             SAMDATA(sc2b->sam_challenge, "", 20),
             sc2b->sam_challenge.length?"], ":"",
             SAMDATA(sc2b->sam_response_prompt, "passcode", 55));

    response_data.data = response;
    response_data.length = sizeof(response);
    kprompt.prompt = prompt;
    kprompt.hidden = 1;
    kprompt.reply = &response_data;

    prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
    krb5int_set_prompt_types(context, &prompt_type);

    if ((retval = ((*prompter)(context, prompter_data, name,
                               banner, 1, &kprompt)))) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        krb5int_set_prompt_types(context, 0);
        return(retval);
    }

    krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL);

    /* Generate salt used by string_to_key() */
    salt = rock->salt;
    if (((int) salt->length == -1) && (salt->data == NULL)) {
        if ((retval =
             krb5_principal2salt(context, request->client, &defsalt))) {
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            return(retval);
        }
        salt = &defsalt;
    } else {
        defsalt.length = 0;
    }

    /* Get encryption key to be used for checksum and sam_response */
    if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
        /* as_key = string_to_key(password) */

        if (rock->as_key->length) {
            krb5_free_keyblock_contents(context, rock->as_key);
            rock->as_key->length = 0;
        }

        /* generate a key using the supplied password */
        retval = krb5_c_string_to_key(context, sc2b->sam_etype,
				      (krb5_data *)*rock->gak_data, salt,
				      rock->as_key);

        if (retval) {
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            if (defsalt.length) free(defsalt.data);
            return(retval);
        }

        if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) {
            /* as_key = combine_key (as_key, string_to_key(SAD)) */
            krb5_keyblock tmp_kb;

            retval = krb5_c_string_to_key(context, sc2b->sam_etype,
                                          &response_data, salt, &tmp_kb);

            if (retval) {
                krb5_free_sam_challenge_2(context, sc2);
                krb5_free_sam_challenge_2_body(context, sc2b);
                if (defsalt.length) free(defsalt.data);
                return(retval);
            }

            /* This should be a call to the crypto library some day */
            /* key types should already match the sam_etype */
            retval = krb5int_c_combine_keys(context, rock->as_key, &tmp_kb,
					    rock->as_key);

            if (retval) {
                krb5_free_sam_challenge_2(context, sc2);
                krb5_free_sam_challenge_2_body(context, sc2b);
                if (defsalt.length) free(defsalt.data);
                return(retval);
            }
            krb5_free_keyblock_contents(context, &tmp_kb);
        }

        if (defsalt.length)
            free(defsalt.data);

    } else {
        /* as_key = string_to_key(SAD) */

        if (rock->as_key->length) {
            krb5_free_keyblock_contents(context, rock->as_key);
            rock->as_key->length = 0;
        }

        /* generate a key using the supplied password */
        retval = krb5_c_string_to_key(context, sc2b->sam_etype,
                                      &response_data, salt, rock->as_key);

        if (defsalt.length)
            free(defsalt.data);

        if (retval) {
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            return(retval);
        }
    }

    /* Now we have a key, verify the checksum on the sam_challenge */

    cksum = sc2->sam_cksum;

    for (; *cksum; cksum++) {
        if (!krb5_c_is_keyed_cksum((*cksum)->checksum_type))
            continue;
        /* Check this cksum */
        retval = krb5_c_verify_checksum(context, rock->as_key,
                                        KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
                                        &sc2->sam_challenge_2_body,
                                        *cksum, &valid_cksum);
        if (retval) {
            krb5_free_data(context, scratch);
            krb5_free_sam_challenge_2(context, sc2);
            krb5_free_sam_challenge_2_body(context, sc2b);
            return(retval);
        }
        if (valid_cksum)
            break;
    }

    if (!valid_cksum) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        /*
         * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
         * can interpret that as "password incorrect", which is probably
         * the best error we can return in this situation.
         */
        return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
    }

    /* fill in enc_sam_response_enc_2 */
    enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
    enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce;
    if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
        enc_sam_response_enc_2.sam_sad = response_data;
    } else {
        enc_sam_response_enc_2.sam_sad.data = NULL;
        enc_sam_response_enc_2.sam_sad.length = 0;
    }

    /* encode and encrypt enc_sam_response_enc_2 with as_key */
    retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2,
                                                &scratch);
    if (retval) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        return(retval);
    }

    /* Fill in sam_response_2 */
    memset(&sr2, 0, sizeof(sr2));
    sr2.sam_type = sc2b->sam_type;
    sr2.sam_flags = sc2b->sam_flags;
    sr2.sam_track_id = sc2b->sam_track_id;
    sr2.sam_nonce = sc2b->sam_nonce;

    /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded   */
    /* enc_sam_response_enc_2 from above */

    retval = krb5_c_encrypt_length(context, rock->as_key->enctype,
				   scratch->length, &ciph_len);
    if (retval) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        krb5_free_data(context, scratch);
        return(retval);
    }
    sr2.sam_enc_nonce_or_sad.ciphertext.length = ciph_len;

    sr2.sam_enc_nonce_or_sad.ciphertext.data =
        (char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length);

    if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        krb5_free_data(context, scratch);
        return(ENOMEM);
    }

    retval = krb5_c_encrypt(context, rock->as_key,
			    KRB5_KEYUSAGE_PA_SAM_RESPONSE, NULL, scratch,
			    &sr2.sam_enc_nonce_or_sad);
    if (retval) {
        krb5_free_sam_challenge_2(context, sc2);
        krb5_free_sam_challenge_2_body(context, sc2b);
        krb5_free_data(context, scratch);
        krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
        return(retval);
    }
    krb5_free_data(context, scratch);
    scratch = NULL;

    /* Encode the sam_response_2 */
    retval = encode_krb5_sam_response_2(&sr2, &scratch);
    krb5_free_sam_challenge_2(context, sc2);
    krb5_free_sam_challenge_2_body(context, sc2b);
    krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);

    if (retval) {
        return (retval);
    }

    /* Almost there, just need to make padata !  */
    sam_padata = malloc(2 * sizeof(*sam_padata));
    if (sam_padata == NULL) {
        krb5_free_data(context, scratch);
        return(ENOMEM);
    }
    sam_padata[0] = malloc(sizeof(krb5_pa_data));
    if (sam_padata[0] == NULL) {
        krb5_free_data(context, scratch);
	free(sam_padata);
        return(ENOMEM);
    }

    sam_padata[0]->magic = KV5M_PA_DATA;
    sam_padata[0]->pa_type = KRB5_PADATA_SAM_RESPONSE_2;
    sam_padata[0]->length = scratch->length;
    sam_padata[0]->contents = (krb5_octet *) scratch->data;
    free(scratch);
    sam_padata[1] = NULL;

    *out_padata = sam_padata;

    return(0);
}
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
main ()
{
    krb5_context context = 0;
    krb5_data  in, in2, out, out2, check, check2, state, signdata;
    krb5_crypto_iov iov[5];
    int i, j, pos;
    unsigned int dummy;
    size_t len;
    krb5_enc_data enc_out, enc_out2;
    krb5_keyblock *keyblock;
    krb5_key key;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    krb5_free_keyblock (context, keyblock);
    free(out.data);
    free(out2.data);
    free(check.data);
    free(check2.data);
    return 0;
}
Exemple #11
0
/* Construct a cookie pa-data item using the cookie values from state, or a
 * trivial "MIT" cookie if no values are set. */
krb5_error_code
kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state,
                     krb5_db_entry *local_tgt,
                     krb5_const_principal client_princ,
                     krb5_pa_data **cookie_out)
{
    krb5_error_code ret;
    krb5_secure_cookie cookie;
    krb5_pa_data **contents = state->out_cookie_padata, *pa;
    krb5_keyblock *key = NULL;
    krb5_timestamp now;
    krb5_enc_data enc;
    krb5_data *der_cookie = NULL;
    krb5_kvno kvno;
    size_t ctlen;

    *cookie_out = NULL;
    memset(&enc, 0, sizeof(enc));

    /* Make a trivial cookie if there are no contents to marshal or we don't
     * have a TGT entry to encrypt them. */
    if (contents == NULL || *contents == NULL || local_tgt == NULL)
        return make_padata(KRB5_PADATA_FX_COOKIE, "MIT", 3, cookie_out);

    ret = get_cookie_key(context, local_tgt, 0, client_princ, &key, &kvno);
    if (ret)
        goto cleanup;

    /* Encode the cookie. */
    ret = krb5_timeofday(context, &now);
    if (ret)
        goto cleanup;
    cookie.time = now;
    cookie.data = contents;
    ret = encode_krb5_secure_cookie(&cookie, &der_cookie);
    if (ret)
        goto cleanup;

    /* Encrypt the cookie in key. */
    ret = krb5_c_encrypt_length(context, key->enctype, der_cookie->length,
                                &ctlen);
    if (ret)
        goto cleanup;
    ret = alloc_data(&enc.ciphertext, ctlen);
    if (ret)
        goto cleanup;
    ret = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_PA_FX_COOKIE, NULL,
                         der_cookie, &enc);
    if (ret)
        goto cleanup;

    /* Construct the cookie pa-data entry. */
    ret = alloc_padata(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length, &pa);
    memcpy(pa->contents, "MIT1", 4);
    store_32_be(kvno, pa->contents + 4);
    memcpy(pa->contents + 8, enc.ciphertext.data, enc.ciphertext.length);
    *cookie_out = pa;

cleanup:
    krb5_free_keyblock(context, key);
    if (der_cookie != NULL) {
        zapfree(der_cookie->data, der_cookie->length);
        free(der_cookie);
    }
    krb5_free_data_contents(context, &enc.ciphertext);
    return ret;
}
Exemple #12
0
/*ARGSUSED*/
static krb5_error_code
krb5_mk_priv_basic(krb5_context context, const krb5_data *userdata, const krb5_keyblock *keyblock, krb5_replay_data *replaydata, krb5_address *local_addr, krb5_address *remote_addr, krb5_pointer i_vector, krb5_data *outbuf)
{
    krb5_error_code 	retval;
    krb5_priv 		privmsg;
    krb5_priv_enc_part 	privmsg_enc_part;
    krb5_data 		*scratch1, *scratch2, ivdata;
    size_t		blocksize, enclen;

    privmsg.enc_part.kvno = 0;	/* XXX allow user-set? */
    privmsg.enc_part.enctype = keyblock->enctype; 

    privmsg_enc_part.user_data = *userdata;
    privmsg_enc_part.s_address = local_addr;
    privmsg_enc_part.r_address = remote_addr;

    /* We should check too make sure one exists. */
    privmsg_enc_part.timestamp  = replaydata->timestamp;
    privmsg_enc_part.usec 	= replaydata->usec;
    privmsg_enc_part.seq_number = replaydata->seq;

    /* start by encoding to-be-encrypted part of the message */
    if ((retval = encode_krb5_enc_priv_part(&privmsg_enc_part, &scratch1)))
	return retval;

    /* put together an eblock for this encryption */
    if ((retval = krb5_c_encrypt_length(context, keyblock->enctype,
					scratch1->length, &enclen)))
	goto clean_scratch;

    privmsg.enc_part.ciphertext.length = enclen;
    if (!(privmsg.enc_part.ciphertext.data =
	  malloc(privmsg.enc_part.ciphertext.length))) {
        retval = ENOMEM;
        goto clean_scratch;
    }

    /* call the encryption routine */
    if (i_vector) {
	if ((retval = krb5_c_block_size(context, keyblock->enctype,
					&blocksize)))
	    goto clean_encpart;

	ivdata.length = blocksize;
	ivdata.data = i_vector;
    }

    if ((retval = krb5_c_encrypt(context, keyblock,
				 KRB5_KEYUSAGE_KRB_PRIV_ENCPART,
				 i_vector?&ivdata:0,
				 scratch1, &privmsg.enc_part)))
	goto clean_encpart;

    if ((retval = encode_krb5_priv(&privmsg, &scratch2)))
        goto clean_encpart;

    *outbuf = *scratch2;
    krb5_xfree(scratch2);
    retval = 0;

clean_encpart:
    memset(privmsg.enc_part.ciphertext.data, 0, 
	   privmsg.enc_part.ciphertext.length); 
    free(privmsg.enc_part.ciphertext.data); 
    privmsg.enc_part.ciphertext.length = 0;
    privmsg.enc_part.ciphertext.data = 0;

clean_scratch:
    memset(scratch1->data, 0, scratch1->length);
    krb5_free_data(context, scratch1); 

    return retval;
}
int Condor_Auth_Kerberos :: wrap(char*  input, 
                                 int    input_len, 
                                 char*& output, 
                                 int&   output_len)
{
    krb5_error_code code;
    krb5_data       in_data;
    krb5_enc_data   out_data;
    int             index, tmp;

	size_t blocksize, encrypted_length;
	char* encrypted_data = 0;

	// make a blank initialization vector
	code = krb5_c_block_size(krb_context_, sessionKey_->enctype, &blocksize);
	if (code) {
		// err
	}

    // Make the input buffer
    in_data.data = input;
    in_data.length = input_len;

    // Make the output buffer
    code = krb5_c_encrypt_length(krb_context_, sessionKey_->enctype, input_len, &encrypted_length);
	if(code) {
		// err
	}

	encrypted_data = (char*)malloc(encrypted_length);
	if (!encrypted_length) {
		// err
	}

    out_data.ciphertext.data = (char*)encrypted_data;
	out_data.ciphertext.length = encrypted_length;

    if ((code = krb5_c_encrypt(krb_context_, sessionKey_, 1024, /* key usage */
				0, &in_data, &out_data)) != 0) {			/* 0 = no ivec */
        output     = 0;
        output_len = 0;
        if (out_data.ciphertext.data) {    
            free(out_data.ciphertext.data);
        }
        dprintf( D_ALWAYS, "KERBEROS: %s\n", error_message(code) );
        return false;
    }
    
    output_len = sizeof(out_data.enctype) +
        sizeof(out_data.kvno)    + 
        sizeof(out_data.ciphertext.length) +
        out_data.ciphertext.length;
    
    output = (char *) malloc(output_len);
    index = 0;
    tmp = htonl(out_data.enctype);
    memcpy(output + index, &tmp, sizeof(out_data.enctype));
    index += sizeof(out_data.enctype);

    tmp = htonl(out_data.kvno);
    memcpy(output + index, &tmp, sizeof(out_data.kvno));
    index += sizeof(out_data.kvno);

    tmp = htonl(out_data.ciphertext.length);
    memcpy(output + index, &tmp, sizeof(out_data.ciphertext.length));
    index += sizeof(out_data.ciphertext.length);

    if (out_data.ciphertext.data) {    
	memcpy(output + index, out_data.ciphertext.data,
		out_data.ciphertext.length);
        free(out_data.ciphertext.data);
    }

    return TRUE;
}
Exemple #14
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 #15
0
/*ARGSUSED*/
static
krb5_error_code pa_sam(krb5_context context,
		       krb5_kdc_req *request,
		       krb5_pa_data *in_padata,
		       krb5_pa_data **out_padata,
		       krb5_data *salt,
		       krb5_data *s2kparams,
		       krb5_enctype *etype,
		       krb5_keyblock *as_key,
		       krb5_prompter_fct prompter,
		       void *prompter_data,
		       krb5_gic_get_as_key_fct gak_fct,
		       void *gak_data)
{
    krb5_error_code		ret;
    krb5_data			tmpsam;
    char			name[100], banner[100];
    char			prompt[100], response[100];
    krb5_data			response_data;
    krb5_prompt			kprompt;
    krb5_prompt_type		prompt_type;
    krb5_data			defsalt;
    krb5_sam_challenge		*sam_challenge = 0;
    krb5_sam_response		sam_response;
    /* these two get encrypted and stuffed in to sam_response */
    krb5_enc_sam_response_enc	enc_sam_response_enc;
    krb5_data *			scratch;
    krb5_pa_data *		pa;
    krb5_enc_data *		enc_data;
    size_t			enclen;

    if (prompter == NULL)
	return (EIO);

    tmpsam.length = in_padata->length;
    tmpsam.data = (char *) in_padata->contents;
    if ((ret = decode_krb5_sam_challenge(&tmpsam, &sam_challenge)))
	return(ret);

    if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
	krb5_xfree(sam_challenge);
	return(KRB5_SAM_UNSUPPORTED);
    }
    /* If we need the password from the user (USE_SAD_AS_KEY not set),	*/
    /* then get it here.  Exception for "old" KDCs with CryptoCard	*/
    /* support which uses the USE_SAD_AS_KEY flag, but still needs pwd	*/

    if (!(sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) ||
	(sam_challenge->sam_type == PA_SAM_TYPE_CRYPTOCARD)) {

	/* etype has either been set by caller or by KRB5_PADATA_ETYPE_INFO */
	/* message from the KDC.  If it is not set, pick an enctype that we */
	/* think the KDC will have for us.                                  */

	if (etype && *etype == 0)
           *etype = ENCTYPE_DES_CBC_CRC;

	if ((ret = (gak_fct)(context, request->client, *etype, prompter,
			prompter_data, salt, s2kparams, as_key, gak_data)))
	   return(ret);
    }

    sprintf(name, "%.*s",
	    SAMDATA(sam_challenge->sam_type_name, "SAM Authentication",
		    sizeof(name) - 1));

    sprintf(banner, "%.*s",
	    SAMDATA(sam_challenge->sam_challenge_label,
		    sam_challenge_banner(sam_challenge->sam_type),
		    sizeof(banner)-1));

    /* sprintf(prompt, "Challenge is [%s], %s: ", challenge, prompt); */
    sprintf(prompt, "%s%.*s%s%.*s",
	    sam_challenge->sam_challenge.length?"Challenge is [":"",
	    SAMDATA(sam_challenge->sam_challenge, "", 20),
	    sam_challenge->sam_challenge.length?"], ":"",
	    SAMDATA(sam_challenge->sam_response_prompt, "passcode", 55));

    response_data.data = response;
    response_data.length = sizeof(response);

    kprompt.prompt = prompt;
    kprompt.hidden = 1;
    kprompt.reply = &response_data;
    prompt_type = KRB5_PROMPT_TYPE_PREAUTH;

    /* PROMPTER_INVOCATION */
    krb5int_set_prompt_types(context, &prompt_type);
    if ((ret = ((*prompter)(context, prompter_data, name,
			   banner, 1, &kprompt)))) {
	krb5_xfree(sam_challenge);
	krb5int_set_prompt_types(context, 0);
	return(ret);
    }
    krb5int_set_prompt_types(context, 0);

    enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce;
    if (sam_challenge->sam_nonce == 0) {
	if ((ret = krb5_us_timeofday(context, 
				&enc_sam_response_enc.sam_timestamp,
				&enc_sam_response_enc.sam_usec))) {
		krb5_xfree(sam_challenge);
		return(ret);
	}

	sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp;
    }

    /* XXX What if more than one flag is set?  */
    if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {

	/* Most of this should be taken care of before we get here.  We */
	/* will need the user's password and as_key to encrypt the SAD	*/
	/* and we want to preserve ordering of user prompts (first	*/
	/* password, then SAM data) so that user's won't be confused.	*/

	if (as_key->length) {
	    krb5_free_keyblock_contents(context, as_key);
	    as_key->length = 0;
	}

	/* generate a salt using the requested principal */

	if ((salt->length == -1) && (salt->data == NULL)) {
	    if ((ret = krb5_principal2salt(context, request->client,
					  &defsalt))) {
		krb5_xfree(sam_challenge);
		return(ret);
	    }

	    salt = &defsalt;
	} else {
	    defsalt.length = 0;
	}

	/* generate a key using the supplied password */

	ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
				   (krb5_data *)gak_data, salt, as_key);

	if (defsalt.length)
	    krb5_xfree(defsalt.data);

	if (ret) {
	    krb5_xfree(sam_challenge);
	    return(ret);
	}

	/* encrypt the passcode with the key from above */

	enc_sam_response_enc.sam_sad = response_data;
    } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {

	/* process the key as password */

	if (as_key->length) {
	    krb5_free_keyblock_contents(context, as_key);
	    as_key->length = 0;
	}

#if 0
	if ((salt->length == -1) && (salt->data == NULL)) {
	    if (ret = krb5_principal2salt(context, request->client,
					  &defsalt)) {
		krb5_xfree(sam_challenge);
		return(ret);
	    }

	    salt = &defsalt;
	} else {
	    defsalt.length = 0;
	}
#else
	defsalt.length = 0;
	salt = NULL;
#endif
	    
	/* XXX As of the passwords-04 draft, no enctype is specified,
	   the server uses ENCTYPE_DES_CBC_MD5. In the future the
	   server should send a PA-SAM-ETYPE-INFO containing the enctype. */

	ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
				   &response_data, salt, as_key);

	if (defsalt.length)
	    krb5_xfree(defsalt.data);

	if (ret) {
	    krb5_xfree(sam_challenge);
	    return(ret);
	}

	enc_sam_response_enc.sam_sad.length = 0;
    } else {
	/* Eventually, combine SAD with long-term key to get
	   encryption key.  */
	return KRB5_PREAUTH_BAD_TYPE;
    }

    /* copy things from the challenge */
    sam_response.sam_nonce = sam_challenge->sam_nonce;
    sam_response.sam_flags = sam_challenge->sam_flags;
    sam_response.sam_track_id = sam_challenge->sam_track_id;
    sam_response.sam_type = sam_challenge->sam_type;
    sam_response.magic = KV5M_SAM_RESPONSE;

    krb5_xfree(sam_challenge);

    /* encode the encoded part of the response */
    if ((ret = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc,
					       &scratch)))
	return(ret);

    /*
     * Solaris Kerberos:  
     * Using new crypto interface now so we can get rid of the
     * old modules.
     */
    if ((ret = krb5_c_encrypt_length(context, as_key->enctype,
				scratch->length, &enclen))) {
	krb5_free_data(context, scratch);
	return(ret);
    }

    enc_data = &sam_response.sam_enc_nonce_or_ts;
    enc_data->magic = KV5M_ENC_DATA;
    enc_data->kvno = 0;
    enc_data->enctype = as_key->enctype;
    enc_data->ciphertext.length = enclen;

    if ((enc_data->ciphertext.data = MALLOC(enclen)) == NULL) {
	enc_data->ciphertext.length = 0;
	krb5_free_data(context, scratch);
	return(ENOMEM);
    }

    if ((ret = krb5_c_encrypt(context, as_key, 0, 0,
	scratch, enc_data))) {
	FREE(enc_data->ciphertext.data, enclen);
	enc_data->ciphertext.data = NULL;
	enc_data->ciphertext.length = 0;
    }

    krb5_free_data(context, scratch);

    if (ret)
	return(ret);

    /* sam_enc_key is reserved for future use */
    sam_response.sam_enc_key.ciphertext.length = 0;

    if ((pa = malloc(sizeof(krb5_pa_data))) == NULL)
	return(ENOMEM);

    if ((ret = encode_krb5_sam_response(&sam_response, &scratch))) {
	free(pa);
	return(ret);
    }

    pa->magic = KV5M_PA_DATA;
    pa->pa_type = KRB5_PADATA_SAM_RESPONSE;
    pa->length = scratch->length;
    pa->contents = (krb5_octet *) scratch->data;

    *out_padata = pa;

    return(0);
}