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

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
...@@ -41,6 +41,9 @@ ...@@ -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 { ...@@ -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 { ...@@ -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) ...@@ -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;
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)) 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, ...@@ -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[] = { ...@@ -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, ...@@ -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, ...@@ -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;
return GSS_S_FAILURE; else
cksumkey = NULL;
if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, if (make_checksum(ctx, ptr, 8, text, 0, cksumkey, &md5cksum))
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE; 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); 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, ...@@ -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, ...@@ -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;
return GSS_S_FAILURE; 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; 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)) 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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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;
return GSS_S_FAILURE; else
cksumkey = NULL;
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, if (make_checksum(kctx, ptr, 8, buf, crypt_offset,
md5cksum.data, md5cksum.len)) cksumkey, &md5cksum))
return GSS_S_FAILURE; return GSS_S_FAILURE;
if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8)) if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
kctx->gk5e->cksumlength))
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 */
......
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