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

Commit 14ae162c authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Trond Myklebust
Browse files

RPCSEC_GSS: Add support for privacy to krb5 rpcsec_gss mechanism.



 Add support for privacy to the krb5 rpcsec_gss mechanism.

 Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
 Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent bfa91516
Loading
Loading
Loading
Loading
+17 −1
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ enum seal_alg {

s32
make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
		   struct xdr_netobj *cksum);
		   int body_offset, struct xdr_netobj *cksum);

u32
krb5_make_token(struct krb5_ctx *context_handle, int qop_req,
@@ -128,6 +128,15 @@ krb5_read_token(struct krb5_ctx *context_handle,
	  struct xdr_netobj *input_token_buffer,
	  struct xdr_buf *message_buffer, int *qop_state);

u32
gss_wrap_kerberos(struct gss_ctx *ctx_id, u32 qop, int offset,
		struct xdr_buf *outbuf, struct page **pages);

u32
gss_unwrap_kerberos(struct gss_ctx *ctx_id, u32 *qop, int offset,
		struct xdr_buf *buf);


u32
krb5_encrypt(struct crypto_tfm * key,
	     void *iv, void *in, void *out, int length);
@@ -136,6 +145,13 @@ u32
krb5_decrypt(struct crypto_tfm * key,
	     void *iv, void *in, void *out, int length); 

int
gss_encrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *outbuf, int offset,
		struct page **pages);

int
gss_decrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *inbuf, int offset);

s32
krb5_make_seq_num(struct crypto_tfm * key,
		int direction,
+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ auth_rpcgss-objs := auth_gss.o gss_generic_token.o \
obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o

rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
	gss_krb5_seqnum.o
	gss_krb5_seqnum.o gss_krb5_wrap.o

obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o

+154 −2
Original line number Diff line number Diff line
@@ -218,7 +218,7 @@ checksummer(struct scatterlist *sg, void *data)
/* checksum the plaintext data and hdrlen bytes of the token header */
s32
make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
		   struct xdr_netobj *cksum)
		   int body_offset, struct xdr_netobj *cksum)
{
	char                            *cksumname;
	struct crypto_tfm               *tfm = NULL; /* XXX add to ctx? */
@@ -243,7 +243,8 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
	crypto_digest_init(tfm);
	buf_to_sg(sg, header, hdrlen);
	crypto_digest_update(tfm, sg, 1);
	process_xdr_buf(body, 0, body->len, checksummer, tfm);
	process_xdr_buf(body, body_offset, body->len - body_offset,
			checksummer, tfm);
	crypto_digest_final(tfm, cksum->data);
	code = 0;
out:
@@ -252,3 +253,154 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
}

EXPORT_SYMBOL(make_checksum);

struct encryptor_desc {
	u8 iv[8]; /* XXX hard-coded blocksize */
	struct crypto_tfm *tfm;
	int pos;
	struct xdr_buf *outbuf;
	struct page **pages;
	struct scatterlist infrags[4];
	struct scatterlist outfrags[4];
	int fragno;
	int fraglen;
};

static int
encryptor(struct scatterlist *sg, void *data)
{
	struct encryptor_desc *desc = data;
	struct xdr_buf *outbuf = desc->outbuf;
	struct page *in_page;
	int thislen = desc->fraglen + sg->length;
	int fraglen, ret;
	int page_pos;

	/* Worst case is 4 fragments: head, end of page 1, start
	 * of page 2, tail.  Anything more is a bug. */
	BUG_ON(desc->fragno > 3);
	desc->infrags[desc->fragno] = *sg;
	desc->outfrags[desc->fragno] = *sg;

	page_pos = desc->pos - outbuf->head[0].iov_len;
	if (page_pos >= 0 && page_pos < outbuf->page_len) {
		/* pages are not in place: */
		int i = (page_pos + outbuf->page_base) >> PAGE_CACHE_SHIFT;
		in_page = desc->pages[i];
	} else {
		in_page = sg->page;
	}
	desc->infrags[desc->fragno].page = in_page;
	desc->fragno++;
	desc->fraglen += sg->length;
	desc->pos += sg->length;

	fraglen = thislen & 7; /* XXX hardcoded blocksize */
	thislen -= fraglen;

	if (thislen == 0)
		return 0;

	ret = crypto_cipher_encrypt_iv(desc->tfm, desc->outfrags, desc->infrags,
					thislen, desc->iv);
	if (ret)
		return ret;
	if (fraglen) {
		desc->outfrags[0].page = sg->page;
		desc->outfrags[0].offset = sg->offset + sg->length - fraglen;
		desc->outfrags[0].length = fraglen;
		desc->infrags[0] = desc->outfrags[0];
		desc->infrags[0].page = in_page;
		desc->fragno = 1;
		desc->fraglen = fraglen;
	} else {
		desc->fragno = 0;
		desc->fraglen = 0;
	}
	return 0;
}

int
gss_encrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset,
		struct page **pages)
{
	int ret;
	struct encryptor_desc desc;

	BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0);

	memset(desc.iv, 0, sizeof(desc.iv));
	desc.tfm = tfm;
	desc.pos = offset;
	desc.outbuf = buf;
	desc.pages = pages;
	desc.fragno = 0;
	desc.fraglen = 0;

	ret = process_xdr_buf(buf, offset, buf->len - offset, encryptor, &desc);
	return ret;
}

EXPORT_SYMBOL(gss_encrypt_xdr_buf);

struct decryptor_desc {
	u8 iv[8]; /* XXX hard-coded blocksize */
	struct crypto_tfm *tfm;
	struct scatterlist frags[4];
	int fragno;
	int fraglen;
};

static int
decryptor(struct scatterlist *sg, void *data)
{
	struct decryptor_desc *desc = data;
	int thislen = desc->fraglen + sg->length;
	int fraglen, ret;

	/* Worst case is 4 fragments: head, end of page 1, start
	 * of page 2, tail.  Anything more is a bug. */
	BUG_ON(desc->fragno > 3);
	desc->frags[desc->fragno] = *sg;
	desc->fragno++;
	desc->fraglen += sg->length;

	fraglen = thislen & 7; /* XXX hardcoded blocksize */
	thislen -= fraglen;

	if (thislen == 0)
		return 0;

	ret = crypto_cipher_decrypt_iv(desc->tfm, desc->frags, desc->frags,
					thislen, desc->iv);
	if (ret)
		return ret;
	if (fraglen) {
		desc->frags[0].page = sg->page;
		desc->frags[0].offset = sg->offset + sg->length - fraglen;
		desc->frags[0].length = fraglen;
		desc->fragno = 1;
		desc->fraglen = fraglen;
	} else {
		desc->fragno = 0;
		desc->fraglen = 0;
	}
	return 0;
}

int
gss_decrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset)
{
	struct decryptor_desc desc;

	/* XXXJBF: */
	BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0);

	memset(desc.iv, 0, sizeof(desc.iv));
	desc.tfm = tfm;
	desc.fragno = 0;
	desc.fraglen = 0;
	return process_xdr_buf(buf, offset, buf->len - offset, decryptor, &desc);
}

EXPORT_SYMBOL(gss_decrypt_xdr_buf);
+7 −0
Original line number Diff line number Diff line
@@ -226,6 +226,8 @@ static struct gss_api_ops gss_kerberos_ops = {
	.gss_import_sec_context	= gss_import_sec_context_kerberos,
	.gss_get_mic		= gss_get_mic_kerberos,
	.gss_verify_mic		= gss_verify_mic_kerberos,
	.gss_wrap		= gss_wrap_kerberos,
	.gss_unwrap		= gss_unwrap_kerberos,
	.gss_delete_sec_context	= gss_delete_sec_context_kerberos,
};

@@ -240,6 +242,11 @@ static struct pf_desc gss_kerberos_pfs[] = {
		.service = RPC_GSS_SVC_INTEGRITY,
		.name = "krb5i",
	},
	[2] = {
		.pseudoflavor = RPC_AUTH_GSS_KRB5P,
		.service = RPC_GSS_SVC_PRIVACY,
		.name = "krb5p",
	},
};

static struct gss_api_mech gss_kerberos_mech = {
+2 −2
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ krb5_make_token(struct krb5_ctx *ctx, int qop_req,
	*(u16 *)(krb5_hdr + 2) = htons(ctx->signalg);
	memset(krb5_hdr + 4, 0xff, 4);

	if (make_checksum(checksum_type, krb5_hdr, 8, text, &md5cksum))
	if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum))
			goto out_err;

	switch (ctx->signalg) {
Loading