Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1f6c07b authored by Kevin Coffman's avatar Kevin Coffman Committed by Trond Myklebust
Browse files

gss_krb5: add ability to have a keyed checksum (hmac)



Encryption types besides DES may use a keyed checksum (hmac).
Modify the make_checksum() function to allow for a key
and take care of enctype-specific processing such as truncating
the resulting hash.

Signed-off-by: default avatarKevin Coffman <kwc@citi.umich.edu>
Signed-off-by: default avatarSteve Dickson <steved@redhat.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 81d4a433
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@
#include <linux/sunrpc/gss_err.h>
#include <linux/sunrpc/gss_asn1.h>

/* Maximum key length (in bytes) for the supported crypto algorithms*/
#define GSS_KRB5_MAX_KEYLEN (32)

/* Maximum checksum function output for the supported crypto algorithms */
#define GSS_KRB5_MAX_CKSUM_LEN  (20)

@@ -74,6 +77,7 @@ struct krb5_ctx {
	const struct gss_krb5_enctype *gk5e; /* enctype-specific info */
	struct crypto_blkcipher	*enc;
	struct crypto_blkcipher	*seq;
	u8			cksum[GSS_KRB5_MAX_KEYLEN];
	s32			endtime;
	u32			seq_send;
	struct xdr_netobj	mech_used;
@@ -159,9 +163,10 @@ enum seal_alg {
	+ GSS_KRB5_TOK_HDR_LEN                                   \
	+ GSS_KRB5_MAX_CKSUM_LEN)

s32
make_checksum(char *, char *header, int hdrlen, struct xdr_buf *body,
		   int body_offset, struct xdr_netobj *cksum);
u32
make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
		struct xdr_buf *body, int body_offset, u8 *cksumkey,
		struct xdr_netobj *cksumout);

u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
		struct xdr_netobj *);
+46 −8
Original line number Diff line number Diff line
@@ -123,21 +123,42 @@ checksummer(struct scatterlist *sg, void *data)
	return crypto_hash_update(desc, sg, sg->length);
}

/* checksum the plaintext data and hdrlen bytes of the token header */
s32
make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body,
		   int body_offset, struct xdr_netobj *cksum)
/*
 * checksum the plaintext data and hdrlen bytes of the token header
 * The checksum is performed over the first 8 bytes of the
 * gss token header and then over the data body
 */
u32
make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
	      struct xdr_buf *body, int body_offset, u8 *cksumkey,
	      struct xdr_netobj *cksumout)
{
	struct hash_desc                desc; /* XXX add to ctx? */
	struct hash_desc                desc;
	struct scatterlist              sg[1];
	int err;
	u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
	unsigned int checksumlen;

	if (cksumout->len < kctx->gk5e->cksumlength) {
		dprintk("%s: checksum buffer length, %u, too small for %s\n",
			__func__, cksumout->len, kctx->gk5e->name);
		return GSS_S_FAILURE;
	}

	desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC);
	desc.tfm = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
	if (IS_ERR(desc.tfm))
		return GSS_S_FAILURE;
	cksum->len = crypto_hash_digestsize(desc.tfm);
	desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;

	checksumlen = crypto_hash_digestsize(desc.tfm);

	if (cksumkey != NULL) {
		err = crypto_hash_setkey(desc.tfm, cksumkey,
					 kctx->gk5e->keylength);
		if (err)
			goto out;
	}

	err = crypto_hash_init(&desc);
	if (err)
		goto out;
@@ -149,8 +170,25 @@ make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body,
			      checksummer, &desc);
	if (err)
		goto out;
	err = crypto_hash_final(&desc, cksum->data);
	err = crypto_hash_final(&desc, checksumdata);
	if (err)
		goto out;

	switch (kctx->gk5e->ctype) {
	case CKSUMTYPE_RSA_MD5:
		err = kctx->gk5e->encrypt(kctx->seq, NULL, checksumdata,
					  checksumdata, checksumlen);
		if (err)
			goto out;
		memcpy(cksumout->data,
		       checksumdata + checksumlen - kctx->gk5e->cksumlength,
		       kctx->gk5e->cksumlength);
		break;
	default:
		BUG();
		break;
	}
	cksumout->len = kctx->gk5e->cksumlength;
out:
	crypto_free_hash(desc.tfm);
	return err ? GSS_S_FAILURE : 0;
+1 −0
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
	  .keylength = 8,
	  .blocksize = 8,
	  .cksumlength = 8,
	  .keyed_cksum = 0,
	},
};

+7 −6
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
	void			*ptr;
	s32			now;
	u32			seq_send;
	u8			*cksumkey;

	dprintk("RPC:       %s\n", __func__);
	BUG_ON(ctx == NULL);
@@ -109,15 +110,15 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,

	ptr = setup_token(ctx, token);

	if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 8,
						text, 0, &md5cksum))
		return GSS_S_FAILURE;
	if (ctx->gk5e->keyed_cksum)
		cksumkey = ctx->cksum;
	else
		cksumkey = NULL;

	if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
			  md5cksum.data, md5cksum.len))
	if (make_checksum(ctx, ptr, 8, text, 0, cksumkey, &md5cksum))
		return GSS_S_FAILURE;

	memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
	memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);

	spin_lock(&krb5_seq_lock);
	seq_send = ctx->seq_send++;
+8 −5
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
	u32			seqnum;
	unsigned char		*ptr = (unsigned char *)read_token->data;
	int			bodysize;
	u8			*cksumkey;

	dprintk("RPC:       krb5_read_token\n");

@@ -108,14 +109,16 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
	if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
		return GSS_S_DEFECTIVE_TOKEN;

	if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 8,
					message_buffer, 0, &md5cksum))
		return GSS_S_FAILURE;
	if (ctx->gk5e->keyed_cksum)
		cksumkey = ctx->cksum;
	else
		cksumkey = NULL;

	if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16))
	if (make_checksum(ctx, ptr, 8, message_buffer, 0,
			  cksumkey, &md5cksum))
		return GSS_S_FAILURE;

	if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN,
	if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
					ctx->gk5e->cksumlength))
		return GSS_S_BAD_SIG;

Loading