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

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
......@@ -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,
......
......@@ -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
......
......@@ -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);
......@@ -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 = {
......
......@@ -116,8 +116,8 @@ 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))
goto out_err;
if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum))
goto out_err;
switch (ctx->signalg) {
case SGN_ALG_DES_MAC_MD5:
......
......@@ -136,7 +136,7 @@ krb5_read_token(struct krb5_ctx *ctx,
switch (signalg) {
case SGN_ALG_DES_MAC_MD5:
ret = make_checksum(checksum_type, ptr - 2, 8,
message_buffer, &md5cksum);
message_buffer, 0, &md5cksum);
if (ret)
goto out;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment