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: Kevin Coffman <kwc@citi.umich.edu> Signed-off-by: Steve Dickson <steved@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
81d4a4333a
commit
e1f6c07b11
|
@ -41,6 +41,9 @@
|
||||||
#include <linux/sunrpc/gss_err.h>
|
#include <linux/sunrpc/gss_err.h>
|
||||||
#include <linux/sunrpc/gss_asn1.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 */
|
/* Maximum checksum function output for the supported crypto algorithms */
|
||||||
#define GSS_KRB5_MAX_CKSUM_LEN (20)
|
#define GSS_KRB5_MAX_CKSUM_LEN (20)
|
||||||
|
|
||||||
|
@ -74,6 +77,7 @@ struct krb5_ctx {
|
||||||
const struct gss_krb5_enctype *gk5e; /* enctype-specific info */
|
const struct gss_krb5_enctype *gk5e; /* enctype-specific info */
|
||||||
struct crypto_blkcipher *enc;
|
struct crypto_blkcipher *enc;
|
||||||
struct crypto_blkcipher *seq;
|
struct crypto_blkcipher *seq;
|
||||||
|
u8 cksum[GSS_KRB5_MAX_KEYLEN];
|
||||||
s32 endtime;
|
s32 endtime;
|
||||||
u32 seq_send;
|
u32 seq_send;
|
||||||
struct xdr_netobj mech_used;
|
struct xdr_netobj mech_used;
|
||||||
|
@ -159,9 +163,10 @@ enum seal_alg {
|
||||||
+ GSS_KRB5_TOK_HDR_LEN \
|
+ GSS_KRB5_TOK_HDR_LEN \
|
||||||
+ GSS_KRB5_MAX_CKSUM_LEN)
|
+ GSS_KRB5_MAX_CKSUM_LEN)
|
||||||
|
|
||||||
s32
|
u32
|
||||||
make_checksum(char *, char *header, int hdrlen, struct xdr_buf *body,
|
make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
|
||||||
int body_offset, struct xdr_netobj *cksum);
|
struct xdr_buf *body, int body_offset, u8 *cksumkey,
|
||||||
|
struct xdr_netobj *cksumout);
|
||||||
|
|
||||||
u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
|
u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
|
||||||
struct xdr_netobj *);
|
struct xdr_netobj *);
|
||||||
|
|
|
@ -123,21 +123,42 @@ checksummer(struct scatterlist *sg, void *data)
|
||||||
return crypto_hash_update(desc, sg, sg->length);
|
return crypto_hash_update(desc, sg, sg->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* checksum the plaintext data and hdrlen bytes of the token header */
|
/*
|
||||||
s32
|
* checksum the plaintext data and hdrlen bytes of the token header
|
||||||
make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body,
|
* The checksum is performed over the first 8 bytes of the
|
||||||
int body_offset, struct xdr_netobj *cksum)
|
* 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];
|
struct scatterlist sg[1];
|
||||||
int err;
|
int err;
|
||||||
|
u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
|
||||||
|
unsigned int checksumlen;
|
||||||
|
|
||||||
desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC);
|
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(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
|
||||||
if (IS_ERR(desc.tfm))
|
if (IS_ERR(desc.tfm))
|
||||||
return GSS_S_FAILURE;
|
return GSS_S_FAILURE;
|
||||||
cksum->len = crypto_hash_digestsize(desc.tfm);
|
|
||||||
desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
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);
|
err = crypto_hash_init(&desc);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -149,8 +170,25 @@ make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body,
|
||||||
checksummer, &desc);
|
checksummer, &desc);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
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:
|
out:
|
||||||
crypto_free_hash(desc.tfm);
|
crypto_free_hash(desc.tfm);
|
||||||
return err ? GSS_S_FAILURE : 0;
|
return err ? GSS_S_FAILURE : 0;
|
||||||
|
|
|
@ -66,6 +66,7 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
|
||||||
.keylength = 8,
|
.keylength = 8,
|
||||||
.blocksize = 8,
|
.blocksize = 8,
|
||||||
.cksumlength = 8,
|
.cksumlength = 8,
|
||||||
|
.keyed_cksum = 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||||
void *ptr;
|
void *ptr;
|
||||||
s32 now;
|
s32 now;
|
||||||
u32 seq_send;
|
u32 seq_send;
|
||||||
|
u8 *cksumkey;
|
||||||
|
|
||||||
dprintk("RPC: %s\n", __func__);
|
dprintk("RPC: %s\n", __func__);
|
||||||
BUG_ON(ctx == NULL);
|
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);
|
ptr = setup_token(ctx, token);
|
||||||
|
|
||||||
if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 8,
|
if (ctx->gk5e->keyed_cksum)
|
||||||
text, 0, &md5cksum))
|
cksumkey = ctx->cksum;
|
||||||
|
else
|
||||||
|
cksumkey = NULL;
|
||||||
|
|
||||||
|
if (make_checksum(ctx, ptr, 8, text, 0, cksumkey, &md5cksum))
|
||||||
return GSS_S_FAILURE;
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
|
memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
|
||||||
md5cksum.data, md5cksum.len))
|
|
||||||
return GSS_S_FAILURE;
|
|
||||||
|
|
||||||
memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
|
|
||||||
|
|
||||||
spin_lock(&krb5_seq_lock);
|
spin_lock(&krb5_seq_lock);
|
||||||
seq_send = ctx->seq_send++;
|
seq_send = ctx->seq_send++;
|
||||||
|
|
|
@ -84,6 +84,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
|
||||||
u32 seqnum;
|
u32 seqnum;
|
||||||
unsigned char *ptr = (unsigned char *)read_token->data;
|
unsigned char *ptr = (unsigned char *)read_token->data;
|
||||||
int bodysize;
|
int bodysize;
|
||||||
|
u8 *cksumkey;
|
||||||
|
|
||||||
dprintk("RPC: krb5_read_token\n");
|
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))
|
if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
|
||||||
return GSS_S_DEFECTIVE_TOKEN;
|
return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
|
||||||
if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 8,
|
if (ctx->gk5e->keyed_cksum)
|
||||||
message_buffer, 0, &md5cksum))
|
cksumkey = ctx->cksum;
|
||||||
|
else
|
||||||
|
cksumkey = NULL;
|
||||||
|
|
||||||
|
if (make_checksum(ctx, ptr, 8, message_buffer, 0,
|
||||||
|
cksumkey, &md5cksum))
|
||||||
return GSS_S_FAILURE;
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16))
|
if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
|
||||||
return GSS_S_FAILURE;
|
|
||||||
|
|
||||||
if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN,
|
|
||||||
ctx->gk5e->cksumlength))
|
ctx->gk5e->cksumlength))
|
||||||
return GSS_S_BAD_SIG;
|
return GSS_S_BAD_SIG;
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
|
||||||
int headlen;
|
int headlen;
|
||||||
struct page **tmp_pages;
|
struct page **tmp_pages;
|
||||||
u32 seq_send;
|
u32 seq_send;
|
||||||
|
u8 *cksumkey;
|
||||||
|
|
||||||
dprintk("RPC: %s\n", __func__);
|
dprintk("RPC: %s\n", __func__);
|
||||||
|
|
||||||
|
@ -205,18 +206,20 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
|
||||||
|
|
||||||
make_confounder(msg_start, blocksize);
|
make_confounder(msg_start, blocksize);
|
||||||
|
|
||||||
|
if (kctx->gk5e->keyed_cksum)
|
||||||
|
cksumkey = kctx->cksum;
|
||||||
|
else
|
||||||
|
cksumkey = NULL;
|
||||||
|
|
||||||
/* XXXJBF: UGH!: */
|
/* XXXJBF: UGH!: */
|
||||||
tmp_pages = buf->pages;
|
tmp_pages = buf->pages;
|
||||||
buf->pages = pages;
|
buf->pages = pages;
|
||||||
if (make_checksum((char *)kctx->gk5e->cksum_name, ptr, 8, buf,
|
if (make_checksum(kctx, ptr, 8, buf, offset + headlen - blocksize,
|
||||||
offset + headlen - blocksize, &md5cksum))
|
cksumkey, &md5cksum))
|
||||||
return GSS_S_FAILURE;
|
return GSS_S_FAILURE;
|
||||||
buf->pages = tmp_pages;
|
buf->pages = tmp_pages;
|
||||||
|
|
||||||
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
|
memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
|
||||||
md5cksum.data, md5cksum.len))
|
|
||||||
return GSS_S_FAILURE;
|
|
||||||
memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
|
|
||||||
|
|
||||||
spin_lock(&krb5_seq_lock);
|
spin_lock(&krb5_seq_lock);
|
||||||
seq_send = kctx->seq_send++;
|
seq_send = kctx->seq_send++;
|
||||||
|
@ -252,6 +255,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
|
||||||
int data_len;
|
int data_len;
|
||||||
int blocksize;
|
int blocksize;
|
||||||
int crypt_offset;
|
int crypt_offset;
|
||||||
|
u8 *cksumkey;
|
||||||
|
|
||||||
dprintk("RPC: gss_unwrap_kerberos\n");
|
dprintk("RPC: gss_unwrap_kerberos\n");
|
||||||
|
|
||||||
|
@ -288,15 +292,17 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
|
||||||
if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset))
|
if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset))
|
||||||
return GSS_S_DEFECTIVE_TOKEN;
|
return GSS_S_DEFECTIVE_TOKEN;
|
||||||
|
|
||||||
if (make_checksum((char *)kctx->gk5e->cksum_name, ptr, 8, buf,
|
if (kctx->gk5e->keyed_cksum)
|
||||||
crypt_offset, &md5cksum))
|
cksumkey = kctx->cksum;
|
||||||
|
else
|
||||||
|
cksumkey = NULL;
|
||||||
|
|
||||||
|
if (make_checksum(kctx, ptr, 8, buf, crypt_offset,
|
||||||
|
cksumkey, &md5cksum))
|
||||||
return GSS_S_FAILURE;
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
|
if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
|
||||||
md5cksum.data, md5cksum.len))
|
kctx->gk5e->cksumlength))
|
||||||
return GSS_S_FAILURE;
|
|
||||||
|
|
||||||
if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8))
|
|
||||||
return GSS_S_BAD_SIG;
|
return GSS_S_BAD_SIG;
|
||||||
|
|
||||||
/* it got through unscathed. Make sure the context is unexpired */
|
/* it got through unscathed. Make sure the context is unexpired */
|
||||||
|
|
Reference in New Issue