static void
test_wrapping(krb5_context context,
	      size_t min_size,
	      size_t max_size,
	      size_t step,
	      krb5_enctype etype)
{
    krb5_error_code ret;
    krb5_keyblock key;
    krb5_crypto crypto;
    krb5_data data;
    char *etype_name;
    void *buf;
    size_t size;

    ret = krb5_generate_random_keyblock(context, etype, &key);
    if (ret)
	krb5_err(context, 1, ret, "krb5_generate_random_keyblock");

    ret = krb5_enctype_to_string(context, etype, &etype_name);
    if (ret)
	krb5_err(context, 1, ret, "krb5_enctype_to_string");

    buf = malloc(max_size);
    if (buf == NULL)
	krb5_errx(context, 1, "out of memory");
    memset(buf, 0, max_size);

    ret = krb5_crypto_init(context, &key, 0, &crypto);
    if (ret)
	krb5_err(context, 1, ret, "krb5_crypto_init");

    for (size = min_size; size < max_size; size += step) {
	size_t wrapped_size;

	ret = krb5_encrypt(context, crypto, 0, buf, size, &data);
	if (ret)
	    krb5_err(context, 1, ret, "encrypt size %lu using %s",
		     (unsigned long)size, etype_name);

	wrapped_size = krb5_get_wrapped_length(context, crypto, size);

	if (wrapped_size != data.length)
	    krb5_errx(context, 1, "calculated wrapped length %lu != "
		      "real wrapped length %lu for data length %lu using "
		      "enctype %s",
		      (unsigned long)wrapped_size,
		      (unsigned long)data.length,
		      (unsigned long)size,
		      etype_name);
	krb5_data_free(&data);
    }

    free(etype_name);
    free(buf);
    krb5_crypto_destroy(context, crypto);
    krb5_free_keyblock_contents(context, &key);
}
Example #2
0
static void
time_encryption(krb5_context context, size_t size,
		krb5_enctype etype, int iterations)
{
    struct timeval tv1, tv2;
    krb5_error_code ret;
    krb5_keyblock key;
    krb5_crypto crypto;
    krb5_data data;
    char *etype_name;
    void *buf;
    int i;

    ret = krb5_generate_random_keyblock(context, etype, &key);
    if (ret)
	krb5_err(context, 1, ret, "krb5_generate_random_keyblock");

    ret = krb5_enctype_to_string(context, etype, &etype_name);
    if (ret)
	krb5_err(context, 1, ret, "krb5_enctype_to_string");

    buf = malloc(size);
    if (buf == NULL)
	krb5_errx(context, 1, "out of memory");
    memset(buf, 0, size);

    ret = krb5_crypto_init(context, &key, 0, &crypto);
    if (ret)
	krb5_err(context, 1, ret, "krb5_crypto_init");

    gettimeofday(&tv1, NULL);

    for (i = 0; i < iterations; i++) {
	ret = krb5_encrypt(context, crypto, 0, buf, size, &data);
	if (ret)
	    krb5_err(context, 1, ret, "encrypt: %d", i);
	krb5_data_free(&data);
    }

    gettimeofday(&tv2, NULL);

    timevalsub(&tv2, &tv1);

    printf("%s size: %7lu iterations: %d time: %3ld.%06ld\n",
	   etype_name, (unsigned long)size, iterations,
	   (long)tv2.tv_sec, (long)tv2.tv_usec);

    free(buf);
    free(etype_name);
    krb5_crypto_destroy(context, crypto);
    krb5_free_keyblock_contents(context, &key);
}
Example #3
0
u32
gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
		struct xdr_netobj *token)
{
	struct krb5_ctx		*ctx = gss_ctx->internal_ctx_id;
	char			cksumdata[16];
	struct xdr_netobj	md5cksum = {.len = 0, .data = cksumdata};
	unsigned char		*ptr, *krb5_hdr, *msg_start;
	s32			now;
	u32			seq_send;

	dprintk("RPC:       gss_krb5_seal\n");
	BUG_ON(ctx == NULL);

	now = get_seconds();

	token->len = g_token_size(&ctx->mech_used, 22);

	ptr = token->data;
	g_make_token_header(&ctx->mech_used, 22, &ptr);

	*ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
	*ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);

	/* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */
	krb5_hdr = ptr - 2;
	msg_start = krb5_hdr + 24;

	*(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5);
	memset(krb5_hdr + 4, 0xff, 4);

	if (make_checksum("md5", krb5_hdr, 8, text, 0, &md5cksum))
		return GSS_S_FAILURE;

	if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
			  md5cksum.data, md5cksum.len))
		return GSS_S_FAILURE;

	memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
	       KRB5_CKSUM_LENGTH);

	spin_lock(&krb5_seq_lock);
	seq_send = ctx->seq_send++;
	spin_unlock(&krb5_seq_lock);

	if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
			       ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))
		return GSS_S_FAILURE;

	return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
}
Example #4
0
static krb5_error_code
storage_to_etext(krb5_context context,
		 krb5_storage *sp,
		 const krb5_keyblock *key, 
		 krb5_data *enc_data)
{
    krb5_error_code ret;
    krb5_crypto crypto;
    krb5_ssize_t size;
    krb5_data data;

    /* multiple of eight bytes */

    size = krb5_storage_seek(sp, 0, SEEK_END);
    if (size < 0)
	return EINVAL;
    size = 8 - (size & 7);

    ret = krb5_storage_write(sp, eightzeros, size);
    if (ret != size)
	return EINVAL;

    ret = krb5_storage_to_data(sp, &data);
    if (ret)
	return ret;

    ret = krb5_crypto_init(context, key, ETYPE_DES_PCBC_NONE, &crypto);
    if (ret) {
	krb5_data_free(&data);
	return ret;
    }

    ret = krb5_encrypt(context, crypto, 0, data.data, data.length, enc_data);

    krb5_data_free(&data);
    krb5_crypto_destroy(context, crypto);

    return ret;
}
Example #5
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_mk_rep(krb5_context context,
	    krb5_auth_context auth_context,
	    krb5_data *outbuf)
{
    krb5_error_code ret;
    AP_REP ap;
    EncAPRepPart body;
    u_char *buf = NULL;
    size_t buf_size;
    size_t len = 0;
    krb5_crypto crypto;

    ap.pvno = 5;
    ap.msg_type = krb_ap_rep;

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

    body.ctime = auth_context->authenticator->ctime;
    body.cusec = auth_context->authenticator->cusec;
    if (auth_context->flags & KRB5_AUTH_CONTEXT_USE_SUBKEY) {
	if (auth_context->local_subkey == NULL) {
	    ret = krb5_auth_con_generatelocalsubkey(context,
						    auth_context,
						    auth_context->keyblock);
	    if(ret) {
		free_EncAPRepPart(&body);
		return ret;
	    }
	}
	ret = krb5_copy_keyblock(context, auth_context->local_subkey,
				 &body.subkey);
	if (ret) {
	    free_EncAPRepPart(&body);
	    return krb5_enomem(context);
	}
    } else
	body.subkey = NULL;
    if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
	if(auth_context->local_seqnumber == 0)
	    krb5_generate_seq_number (context,
				      auth_context->keyblock,
				      &auth_context->local_seqnumber);
	ALLOC(body.seq_number, 1);
	if (body.seq_number == NULL) {
	    free_EncAPRepPart(&body);
	    return krb5_enomem(context);
	}
	*(body.seq_number) = auth_context->local_seqnumber;
    } else
	body.seq_number = NULL;

    ap.enc_part.etype = auth_context->keyblock->keytype;
    ap.enc_part.kvno  = NULL;

    ASN1_MALLOC_ENCODE(EncAPRepPart, buf, buf_size, &body, &len, ret);
    free_EncAPRepPart (&body);
    if(ret)
	return ret;
    if (buf_size != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");
    ret = krb5_crypto_init(context, auth_context->keyblock,
			   0 /* ap.enc_part.etype */, &crypto);
    if (ret) {
	free (buf);
	return ret;
    }
    ret = krb5_encrypt (context,
			crypto,
			KRB5_KU_AP_REQ_ENC_PART,
			buf + buf_size - len,
			len,
			&ap.enc_part.cipher);
    krb5_crypto_destroy(context, crypto);
    free(buf);
    if (ret)
	return ret;

    ASN1_MALLOC_ENCODE(AP_REP, outbuf->data, outbuf->length, &ap, &len, ret);
    if (ret == 0 && outbuf->length != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");
    free_AP_REP (&ap);
    return ret;
}
Example #6
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_build_authenticator (krb5_context context,
			   krb5_auth_context auth_context,
			   krb5_enctype enctype,
			   krb5_creds *cred,
			   Checksum *cksum,
			   krb5_data *result,
			   krb5_key_usage usage)
{
    Authenticator auth;
    u_char *buf = NULL;
    size_t buf_size;
    size_t len = 0;
    krb5_error_code ret;
    krb5_crypto crypto;

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

    auth.authenticator_vno = 5;
    copy_Realm(&cred->client->realm, &auth.crealm);
    copy_PrincipalName(&cred->client->name, &auth.cname);

    krb5_us_timeofday (context, &auth.ctime, &auth.cusec);

    ret = krb5_auth_con_getlocalsubkey(context, auth_context, &auth.subkey);
    if(ret)
	goto fail;

    if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
	if(auth_context->local_seqnumber == 0)
	    krb5_generate_seq_number (context,
				      &cred->session,
				      &auth_context->local_seqnumber);
	ALLOC(auth.seq_number, 1);
	if(auth.seq_number == NULL) {
	    ret = ENOMEM;
	    goto fail;
	}
	*auth.seq_number = auth_context->local_seqnumber;
    } else
	auth.seq_number = NULL;
    auth.authorization_data = NULL;

    if (cksum) {
	ALLOC(auth.cksum, 1);
	if (auth.cksum == NULL) {
	    ret = ENOMEM;
	    goto fail;
	}
	ret = copy_Checksum(cksum, auth.cksum);
	if (ret)
	    goto fail;

	if (auth.cksum->cksumtype == CKSUMTYPE_GSSAPI) {
	    /*
	     * This is not GSS-API specific, we only enable it for
	     * GSS for now
	     */
	    ret = make_etypelist(context, &auth.authorization_data);
	    if (ret)
		goto fail;
	}
    }

    /* XXX - Copy more to auth_context? */

    auth_context->authenticator->ctime = auth.ctime;
    auth_context->authenticator->cusec = auth.cusec;

    ASN1_MALLOC_ENCODE(Authenticator, buf, buf_size, &auth, &len, ret);
    if (ret)
	goto fail;
    if(buf_size != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    ret = krb5_crypto_init(context, &cred->session, enctype, &crypto);
    if (ret)
	goto fail;
    ret = krb5_encrypt (context,
			crypto,
			usage /* KRB5_KU_AP_REQ_AUTH */,
			buf,
			len,
			result);
    krb5_crypto_destroy(context, crypto);

    if (ret)
	goto fail;

 fail:
    free_Authenticator (&auth);
    free (buf);

    return ret;
}
Example #7
0
krb5_error_code
kcm_store_io(krb5_context context,
	     krb5_uuid uuid,
	     void *ptr,
	     size_t length,
	     krb5_data *data,
	     bool encrypt)
{
    xtsEncrypt_InStruct_t xtsEncrypt_InStruct;
    size_t inseed_size = 64;
    io_connect_t conn;
    kern_return_t kr;
    uint8_t *inseed;
    krb5_crypto crypto = NULL;
    krb5_error_code ret;
    
    krb5_data_zero(data);

    inseed = malloc(inseed_size);
    if (inseed == NULL)
	err(1, "malloc");

    memset(inseed, 0, inseed_size);
    
    conn = openiodev();
    if (conn == IO_OBJECT_NULL) {
	free(inseed);
	return EINVAL;
    }

    uuid_copy(xtsEncrypt_InStruct.key_uuid, uuid);
    xtsEncrypt_InStruct.bufferAddress = (uint64_t) (intptr_t) inseed;
    xtsEncrypt_InStruct.bufferLength = (uint64_t) inseed_size;
    memset(xtsEncrypt_InStruct.tweak, 0, XTS_TWEAK_BYTES);
    
    kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_xtsEncrypt, 
			     NULL, 0, 
			     & xtsEncrypt_InStruct, sizeof(xtsEncrypt_InStruct), 
			     NULL, 0,
			     NULL, 0);
    closeiodev(conn);
    if (kr != KERN_SUCCESS) {
	free(inseed);
	return EINVAL;
    }
    
    CC_SHA256(inseed, (CC_LONG)inseed_size, inseed);

    krb5_keyblock keyblock;
    keyblock.keytype = ETYPE_AES128_CTS_HMAC_SHA1_96;
    keyblock.keyvalue.data = inseed;
    keyblock.keyvalue.length = 16;
    
    ret = krb5_crypto_init(context, &keyblock, 0, &crypto);
    free(inseed);
    if (ret)
	return ret;

    if (encrypt)
	ret = krb5_encrypt(context, crypto, 1, ptr, length, data);
    else
	ret = krb5_decrypt(context, crypto, 1, ptr, length, data);

    krb5_crypto_destroy(context, crypto);
    
    return ret;
}
Example #8
0
u32
krb5_make_token(struct krb5_ctx *ctx, int qop_req,
		   struct xdr_netobj * text, struct xdr_netobj * token,
		   int toktype)
{
	s32			checksum_type;
	struct xdr_netobj	md5cksum = {.len = 0, .data = NULL};
	int			blocksize = 0, tmsglen;
	unsigned char		*ptr, *krb5_hdr, *msg_start;
	s32			now;

	dprintk("RPC: gss_krb5_seal");

	now = jiffies;

	if (qop_req != 0)
		goto out_err;

	switch (ctx->signalg) {
		case SGN_ALG_DES_MAC_MD5:
			checksum_type = CKSUMTYPE_RSA_MD5;
			break;
		default:
			dprintk("RPC: gss_krb5_seal: ctx->signalg %d not"
				" supported\n", ctx->signalg);
			goto out_err;
	}
	if (ctx->sealalg != SEAL_ALG_NONE && ctx->sealalg != SEAL_ALG_DES) {
		dprintk("RPC: gss_krb5_seal: ctx->sealalg %d not supported\n",
			ctx->sealalg);
		goto out_err;
	}

	if (toktype == KG_TOK_WRAP_MSG) {
		blocksize = crypto_tfm_alg_blocksize(ctx->enc);
		tmsglen = blocksize + text->len
			+ gss_krb5_padding(blocksize, blocksize + text->len);
	} else {
		tmsglen = 0;
	}

	token->len = g_token_size(&ctx->mech_used, 22 + tmsglen);
	if ((token->data = kmalloc(token->len, GFP_KERNEL)) == NULL)
		goto out_err;

	ptr = token->data;
	g_make_token_header(&ctx->mech_used, 22 + tmsglen, &ptr, toktype);

	/* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */
	krb5_hdr = ptr - 2;
	msg_start = krb5_hdr + 24;

	*(u16 *)(krb5_hdr + 2) = htons(ctx->signalg);
	memset(krb5_hdr + 4, 0xff, 4);
	if (toktype == KG_TOK_WRAP_MSG)
		*(u16 *)(krb5_hdr + 4) = htons(ctx->sealalg);

	if (toktype == KG_TOK_WRAP_MSG) {
		unsigned char pad = gss_krb5_padding(blocksize, text->len);

		get_random_bytes(msg_start, blocksize); /* "confounder" */
		memcpy(msg_start + blocksize, text->data, text->len);

		memset(msg_start + blocksize + text->len, pad, pad);

		if (compute_checksum(checksum_type, krb5_hdr, msg_start,
				     tmsglen, &md5cksum))
			goto out_err;

		if (krb5_encrypt(ctx->enc, NULL, msg_start, msg_start,
					tmsglen))
			goto out_err;

	} else { /* Sign only.  */
		if (compute_checksum(checksum_type, krb5_hdr, text->data,
					text->len, &md5cksum))
			goto out_err;
	}

	switch (ctx->signalg) {
	case SGN_ALG_DES_MAC_MD5:
		if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
				  md5cksum.data, md5cksum.len))
			goto out_err;
		memcpy(krb5_hdr + 16,
		       md5cksum.data + md5cksum.len - CKSUM_SIZE, CKSUM_SIZE);

		dprintk("make_seal_token: cksum data: \n");
		print_hexl((u32 *) (krb5_hdr + 16), CKSUM_SIZE, 0);
		break;
	default:
		BUG();
	}

	kfree(md5cksum.data);

	if ((krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
			       ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8)))
		goto out_err;

	ctx->seq_send++;

	return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE);
out_err:
	if (md5cksum.data) kfree(md5cksum.data);
	if (token->data) kfree(token->data);
	token->data = 0;
	token->len = 0;
	return GSS_S_FAILURE;
}
Example #9
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_mk_priv(krb5_context context,
             krb5_auth_context auth_context,
             const krb5_data *userdata,
             krb5_data *outbuf,
             krb5_replay_data *outdata)
{
    krb5_error_code ret;
    KRB_PRIV s;
    EncKrbPrivPart part;
    u_char *buf = NULL;
    size_t buf_size;
    size_t len = 0;
    krb5_crypto crypto;
    krb5_keyblock *key;
    krb5_replay_data rdata;

    if ((auth_context->flags &
            (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
            outdata == NULL)
        return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */

    if (auth_context->local_subkey)
        key = auth_context->local_subkey;
    else if (auth_context->remote_subkey)
        key = auth_context->remote_subkey;
    else
        key = auth_context->keyblock;

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

    part.user_data = *userdata;

    krb5_us_timeofday (context, &rdata.timestamp, &rdata.usec);

    if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
        part.timestamp = &rdata.timestamp;
        part.usec      = &rdata.usec;
    } else {
        part.timestamp = NULL;
        part.usec      = NULL;
    }

    if (auth_context->flags & KRB5_AUTH_CONTEXT_RET_TIME) {
        outdata->timestamp = rdata.timestamp;
        outdata->usec = rdata.usec;
    }

    if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
        rdata.seq = auth_context->local_seqnumber;
        part.seq_number = &rdata.seq;
    } else
        part.seq_number = NULL;

    if (auth_context->flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)
        outdata->seq = auth_context->local_seqnumber;

    part.s_address = auth_context->local_address;
    part.r_address = auth_context->remote_address;

    krb5_data_zero (&s.enc_part.cipher);

    ASN1_MALLOC_ENCODE(EncKrbPrivPart, buf, buf_size, &part, &len, ret);
    if (ret)
        goto fail;
    if (buf_size != len)
        krb5_abortx(context, "internal error in ASN.1 encoder");

    s.pvno = 5;
    s.msg_type = krb_priv;
    s.enc_part.etype = key->keytype;
    s.enc_part.kvno = NULL;

    ret = krb5_crypto_init(context, key, 0, &crypto);
    if (ret) {
        free (buf);
        return ret;
    }
    ret = krb5_encrypt (context,
                        crypto,
                        KRB5_KU_KRB_PRIV,
                        buf + buf_size - len,
                        len,
                        &s.enc_part.cipher);
    krb5_crypto_destroy(context, crypto);
    if (ret) {
        free(buf);
        return ret;
    }
    free(buf);


    ASN1_MALLOC_ENCODE(KRB_PRIV, buf, buf_size, &s, &len, ret);
    if (ret)
        goto fail;
    if (buf_size != len)
        krb5_abortx(context, "internal error in ASN.1 encoder");

    krb5_data_free (&s.enc_part.cipher);

    ret = krb5_data_copy(outbuf, buf + buf_size - len, len);
    if (ret) {
        free(buf);
        return krb5_enomem(context);
    }
    free (buf);
    if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
        auth_context->local_seqnumber =
            (auth_context->local_seqnumber + 1) & 0xFFFFFFFF;
    return 0;

fail:
    free (buf);
    krb5_data_free (&s.enc_part.cipher);
    return ret;
}
Example #10
0
u32
krb5_read_token(struct krb5_ctx *ctx,
		struct xdr_netobj *read_token,
		struct xdr_netobj *message_buffer,
		int *qop_state, int toktype)
{
	s32			code;
	int			tmsglen = 0;
	int			conflen = 0;
	int			signalg;
	int			sealalg;
	struct xdr_netobj	token = {.len = 0, .data = NULL};
	s32			checksum_type;
	struct xdr_netobj	cksum;
	struct xdr_netobj	md5cksum = {.len = 0, .data = NULL};
	struct xdr_netobj	plaind;
	char			*data_ptr;
	s32			now;
	unsigned char		*plain = NULL;
	int			cksum_len = 0;
	int			plainlen = 0;
	int			direction;
	s32			seqnum;
	unsigned char		*ptr = (unsigned char *)read_token->data;
	int			bodysize;
	u32			ret = GSS_S_DEFECTIVE_TOKEN;

	dprintk("RPC: krb5_read_token\n");

	if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
					&bodysize, &ptr, toktype,
					read_token->len))
		goto out;

	if (toktype == KG_TOK_WRAP_MSG) {
		message_buffer->len = 0;
		message_buffer->data = NULL;
	}

	/* get the sign and seal algorithms */

	signalg = ptr[0] + (ptr[1] << 8);
	sealalg = ptr[2] + (ptr[3] << 8);

	/* Sanity checks */

	if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
		goto out;

	if (((toktype != KG_TOK_WRAP_MSG) && (sealalg != 0xffff)) ||
	    ((toktype == KG_TOK_WRAP_MSG) && (sealalg == 0xffff)))
		goto out;

	/* in the current spec, there is only one valid seal algorithm per
	   key type, so a simple comparison is ok */

	if ((toktype == KG_TOK_WRAP_MSG) && !(sealalg == ctx->sealalg))
		goto out;

	/* there are several mappings of seal algorithms to sign algorithms,
	   but few enough that we can try them all. */

	if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
	    (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
	    (ctx->sealalg == SEAL_ALG_DES3KD &&
	     signalg != SGN_ALG_HMAC_SHA1_DES3_KD))
		goto out;

	/* starting with a single alg */
	switch (signalg) {
	case SGN_ALG_DES_MAC_MD5:
		cksum_len = 8;
		break;
	default:
		goto out;
	}

	if (toktype == KG_TOK_WRAP_MSG)
		tmsglen = bodysize - (14 + cksum_len);

	/* get the token parameters */

	/* decode the message, if WRAP */

	if (toktype == KG_TOK_WRAP_MSG) {
		dprintk("RPC: krb5_read_token KG_TOK_WRAP_MSG\n");

		plain = kmalloc(tmsglen, GFP_KERNEL);
		ret = GSS_S_FAILURE;
		if (plain ==  NULL)
			goto out;

		code = krb5_decrypt(ctx->enc, NULL,
				   ptr + 14 + cksum_len, plain,
				   tmsglen);
		if (code)
			goto out;

		plainlen = tmsglen;

		conflen = crypto_tfm_alg_blocksize(ctx->enc);
		token.len = tmsglen - conflen - plain[tmsglen - 1];

		if (token.len) {
			token.data = kmalloc(token.len, GFP_KERNEL);
			if (token.data == NULL)
				goto out;
			memcpy(token.data, plain + conflen, token.len);
		}

	} else if (toktype == KG_TOK_MIC_MSG) {
		dprintk("RPC: krb5_read_token KG_TOK_MIC_MSG\n");
		token = *message_buffer;
		plain = token.data;
		plainlen = token.len;
	} else {
		token.len = 0;
		token.data = NULL;
		plain = token.data;
		plainlen = token.len;
	}

	dprintk("RPC krb5_read_token: token.len %d plainlen %d\n", token.len,
		plainlen);

	/* compute the checksum of the message */

	/* initialize the the cksum */
	switch (signalg) {
	case SGN_ALG_DES_MAC_MD5:
		checksum_type = CKSUMTYPE_RSA_MD5;
		break;
	default:
		ret = GSS_S_DEFECTIVE_TOKEN;
		goto out;
	}

	switch (signalg) {
	case SGN_ALG_DES_MAC_MD5:
		dprintk("RPC krb5_read_token SGN_ALG_DES_MAC_MD5\n");
		/* compute the checksum of the message.
		 * 8 = bytes of token body to be checksummed according to spec 
		 */

		data_ptr = kmalloc(8 + plainlen, GFP_KERNEL);
		ret = GSS_S_FAILURE;
		if (!data_ptr)
			goto out;

		memcpy(data_ptr, ptr - 2, 8);
		memcpy(data_ptr + 8, plain, plainlen);

		plaind.len = 8 + plainlen;
		plaind.data = data_ptr;

		code = krb5_make_checksum(checksum_type,
					    &plaind, &md5cksum);

		kfree(data_ptr);

		if (code)
			goto out;

		code = krb5_encrypt(ctx->seq, NULL, md5cksum.data,
					  md5cksum.data, 16);
		if (code)
			goto out;

		if (signalg == 0)
			cksum.len = 8;
		else
			cksum.len = 16;
		cksum.data = md5cksum.data + 16 - cksum.len;

		dprintk
		    ("RPC: krb5_read_token: memcmp digest cksum.len %d:\n",
		     cksum.len);
		dprintk("          md5cksum.data\n");
		print_hexl((u32 *) md5cksum.data, 16, 0);
		dprintk("          cksum.data:\n");
		print_hexl((u32 *) cksum.data, cksum.len, 0);
		{
			u32 *p;

			(u8 *) p = ptr + 14;
			dprintk("          ptr+14:\n");
			print_hexl(p, cksum.len, 0);
		}

		code = memcmp(cksum.data, ptr + 14, cksum.len);
		break;
	default:
		ret = GSS_S_DEFECTIVE_TOKEN;
		goto out;
	}

	ret = GSS_S_BAD_SIG;
	if (code)
		goto out;

	/* it got through unscathed.  Make sure the context is unexpired */

	if (toktype == KG_TOK_WRAP_MSG)
		*message_buffer = token;

	if (qop_state)
		*qop_state = GSS_C_QOP_DEFAULT;

	now = jiffies;

	ret = GSS_S_CONTEXT_EXPIRED;
	if (now > ctx->endtime)
		goto out;

	/* do sequencing checks */

	ret = GSS_S_BAD_SIG;
	if ((code = krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction,
				   &seqnum)))
		goto out;

	if ((ctx->initiate && direction != 0xff) ||
	    (!ctx->initiate && direction != 0))
		goto out;

	ret = GSS_S_COMPLETE;
out:
	if (md5cksum.data) kfree(md5cksum.data);
	if (toktype == KG_TOK_WRAP_MSG) {
		if (plain) kfree(plain);
		if (ret && token.data) kfree(token.data);
	}
	return ret;
}
Example #11
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;
}
Example #12
0
int main(int argc, char **argv)
{
	int log_level = 0;
	char *ap_req_str = NULL;
	char *plain_text_str;
	unsigned char *plain_text;
	size_t plain_text_len;

	/* krb5 */
	krb5_error_code ret;
	krb5_context context;
	krb5_auth_context auth_context;
	char *princ_str_tn = "kink/tn.example.com";
	krb5_principal princ_tn;
	char *princ_str_nut = "kink/nut.example.com";
	krb5_principal princ_nut;
	char *princ_str_krbtgt = "krbtgt/EXAMPLE.COM";
	krb5_principal princ_krbtgt;
	krb5_ccache ccache;
	krb5_keytab keytab;
	krb5_creds creds_tgt;
	krb5_data ap_req;
	krb5_data cipher_text;

	prog = (const char *) basename(argv[0]);
	if (prog == NULL) {
		fprintf(stderr,
			"basename: %s -- %s\n", strerror(errno), argv[0]);

		return(0);
		/* NOTREACHED */
	}

	{
		int ch = 0;

		while ((ch = getopt(argc, argv, "dq:")) != -1) {
			switch (ch) {
			case 'd':
				log_level++;
				break;
			case 'q':
				ap_req_str = optarg;
				break;
			default:
				usage();
				/* NOTREACHED */

				break;
			}
		}

		argc -= optind;
		argv += optind;
	}

	if (!argc) {
		usage();
		/* NOTREACHED */
	}
	plain_text_str = argv[0];

	{
		printf("DBG: %s starts arg(%s)\n", prog, plain_text_str);
	}

	/* prepare encrypted data */
	{
		{ /* stdout */
			printf("std:plain_text:%s\n", plain_text_str);
		}
		plain_text_len = strlen(plain_text_str);
		plain_text_len = plain_text_len/2 + plain_text_len%2;
		plain_text = (unsigned char *)malloc(plain_text_len);
		memset(plain_text, 0, plain_text_len);
		plain_text = hex2data(plain_text_str, plain_text);
	}

	if (ap_req_str != NULL) {
		hex2krb5data(ap_req_str, &ap_req);
		if (log_level) {
			dump_krb5_data(&ap_req);
		}
		{ /* stdout */
			int i = 0;
			unsigned char *p;
			p = (unsigned char *)ap_req.data;
			printf("std:ap_req:");
			for (i = 0; i < ap_req.length; i++) {
				printf("%02x", *p++);
			}
			printf("\n");
		}
	}

	/* prepare krb5 */
	{
		/** init context */
		ret = krb5_init_context(&context);
		if (ret != 0) {
			printf("ERR:krb5_init_context:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/** setup principals */
		ret = krb5_parse_name(context, princ_str_tn, &princ_tn);
		if (ret != 0) {
			printf("ERR:krb5_parse_name:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		ret = krb5_parse_name(context, princ_str_nut, &princ_nut);
		if (ret != 0) {
			printf("ERR:krb5_parse_name:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		ret = krb5_parse_name(context, princ_str_krbtgt, &princ_krbtgt);
		if (ret != 0) {
			printf("ERR:krb5_parse_name:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/** prepare credential cache */
		ret = krb5_cc_default(context, &ccache);
		if (ret != 0) {
			printf("ERR:krb5_cc_default:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/** prepare keytab */
		/*ret = krb5_kt_resolve(context, "/usr/local/var/krb5kdc/kadm5.keytab", &keytab);*/
		ret = krb5_kt_default(context, &keytab);
		if (ret != 0) {
			/* printf("ERR:krb5_kt_default:%s", krb5_get_err_text(context, ret)); */
			printf("ERR:krb5_kt_resolve:%s", krb5_get_err_text(context, ret));
			return(ret);
		}

	}

	/* get TGT */
	/* just only retrieve TGT from credential cache */
	{
		krb5_creds mcreds;
		memset(&mcreds, 0, sizeof(mcreds));
		mcreds.client = princ_tn;
		mcreds.server = princ_krbtgt;

		ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcreds, &creds_tgt);
		if (ret != 0) {
			printf("ERR:krb5_cc_retrieve_cred:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
	}

	/* prepare authentiation context */
	{
		ret = krb5_auth_con_init(context, &auth_context);
		if (ret != 0) {
			printf("ERR:krb5_auth_con_init:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		ret = krb5_auth_con_setflags(context, auth_context,
					     KRB5_AUTH_CONTEXT_DO_SEQUENCE);
		if (ret != 0) {
			printf("ERR:krb5_auth_con_setflags:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/* if USE_SKEY */
		/*
		ret = krb5_auth_con_setuserkey(context, auth_context, &creds_tgt.session);
		if (ret != 0) {
			printf("ERR:krb5_auth_con_setuseruserkey:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		*/
	}

	/* set keyblock in auth_context */
	if (ap_req_str != NULL) {
		krb5_ticket *ticket;
		krb5_flags ap_req_options;
		
		ap_req_options = AP_OPTS_MUTUAL_REQUIRED;
		ticket = NULL;
		ret = krb5_rd_req(context,
				  &auth_context,
				  &ap_req,
				  NULL,
				  keytab,
				  &ap_req_options,
				  &ticket);
		if (log_level) {
			printf("info: ticket.ticket.key is SKEYID_d\n");
			/*dump_krb5_ticket(context, *ticket);*/
		}
		if (log_level) {
			printf("ap_req_opt (%d)\n", ap_req_options);
		}
		if (ret != 0) {
			printf("ERR:krb5_rd_req:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		if (log_level) {
			dump_krb5_keyblock(auth_context->keyblock);
		}

		krb5_free_ticket(context, ticket);
	}
	else {
		krb5_creds mcreds;
		krb5_creds *cred;
		krb5_creds cred_copy;

		memset(&mcreds, 0, sizeof(mcreds));
		mcreds.client = princ_tn;
		mcreds.server = princ_nut;

		ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, &mcreds, &cred);
		if (ret != 0) {
			printf("ERR:krb5_get_credentials:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/* mk_req_extends reallocate cred, so use a copy */
		ret = krb5_copy_creds_contents(context,
					       (const krb5_creds *)cred,
					       &cred_copy);
		if (ret != 0) {
			printf("ERR:krb5_copy_creds_contents:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/*
		 * If auth_con == NULL, one is allocated.
		 * This is used later. (keyblock is used to decrypt AP_REP)
		 */
		ret = krb5_mk_req_extended(context,
					   &auth_context,
					   AP_OPTS_MUTUAL_REQUIRED,
					   NULL /* in_data */,
					   &cred_copy,
					   &ap_req);
		if (ret != 0) {
			printf("ERR:krb5_mk_req_extended:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
	}

	/* encrypt */
	{
		krb5_crypto crypto;

		ret = krb5_crypto_init(context,
				       auth_context->keyblock,
				       auth_context->keyblock->keytype,
				       &crypto);
		if (ret != 0) {
			printf("ERR:krb5_crypto_init:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		ret = krb5_encrypt(context,
				   crypto,
				   39, /* usage */
				   plain_text,
				   plain_text_len,
				   &cipher_text);
		if (ret != 0) {
			printf("ERR:krb5_encrypt:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		{ /* stdout */
			int i = 0;
			unsigned char *p;
			p = (unsigned char *)cipher_text.data;
			printf("std:cipher_text:");
			for (i = 0; i < cipher_text.length; i++) {
				printf("%02x", *p++);
			}
			printf("\n");
		}

		krb5_crypto_destroy(context, crypto);
	}

	/* clenaup */
	{
		/*free(plain_text);*/
		/*krb5_data_free(&ap_req);*/
		krb5_free_cred_contents(context, &creds_tgt);

		ret = krb5_kt_close(context, keytab);
		if (ret != 0) {
			printf("ERR:krb5_kt_close:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		ret = krb5_cc_close(context, ccache);
		if (ret != 0) {
			printf("ERR:krb5_cc_close:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		krb5_free_principal(context, princ_krbtgt);
		krb5_free_principal(context, princ_nut);
		krb5_free_principal(context, princ_tn);
		krb5_free_context(context);
	}

	return(0);
}