aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Coffman <kwc@citi.umich.edu>2010-03-17 13:02:52 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-05-14 15:09:16 -0400
commite1f6c07b1160ef28e8754d12e6c03288dd9d5ca8 (patch)
tree5be1f97a1a51feaed4bed2b4a83a568c94921faf
parent81d4a4333a1dfd6070f046265d928bb4c79aff88 (diff)
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>
-rw-r--r--include/linux/sunrpc/gss_krb5.h11
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c54
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c1
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seal.c13
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_unseal.c13
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c30
6 files changed, 88 insertions, 34 deletions
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index f94935599d13..abf26efd44ac 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -41,6 +41,9 @@
41#include <linux/sunrpc/gss_err.h> 41#include <linux/sunrpc/gss_err.h>
42#include <linux/sunrpc/gss_asn1.h> 42#include <linux/sunrpc/gss_asn1.h>
43 43
44/* Maximum key length (in bytes) for the supported crypto algorithms*/
45#define GSS_KRB5_MAX_KEYLEN (32)
46
44/* Maximum checksum function output for the supported crypto algorithms */ 47/* Maximum checksum function output for the supported crypto algorithms */
45#define GSS_KRB5_MAX_CKSUM_LEN (20) 48#define GSS_KRB5_MAX_CKSUM_LEN (20)
46 49
@@ -74,6 +77,7 @@ struct krb5_ctx {
74 const struct gss_krb5_enctype *gk5e; /* enctype-specific info */ 77 const struct gss_krb5_enctype *gk5e; /* enctype-specific info */
75 struct crypto_blkcipher *enc; 78 struct crypto_blkcipher *enc;
76 struct crypto_blkcipher *seq; 79 struct crypto_blkcipher *seq;
80 u8 cksum[GSS_KRB5_MAX_KEYLEN];
77 s32 endtime; 81 s32 endtime;
78 u32 seq_send; 82 u32 seq_send;
79 struct xdr_netobj mech_used; 83 struct xdr_netobj mech_used;
@@ -159,9 +163,10 @@ enum seal_alg {
159 + GSS_KRB5_TOK_HDR_LEN \ 163 + GSS_KRB5_TOK_HDR_LEN \
160 + GSS_KRB5_MAX_CKSUM_LEN) 164 + GSS_KRB5_MAX_CKSUM_LEN)
161 165
162s32 166u32
163make_checksum(char *, char *header, int hdrlen, struct xdr_buf *body, 167make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
164 int body_offset, struct xdr_netobj *cksum); 168 struct xdr_buf *body, int body_offset, u8 *cksumkey,
169 struct xdr_netobj *cksumout);
165 170
166u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *, 171u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
167 struct xdr_netobj *); 172 struct xdr_netobj *);
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index ccd5236953f7..cae04d7a45a5 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -123,21 +123,42 @@ checksummer(struct scatterlist *sg, void *data)
123 return crypto_hash_update(desc, sg, sg->length); 123 return crypto_hash_update(desc, sg, sg->length);
124} 124}
125 125
126/* checksum the plaintext data and hdrlen bytes of the token header */ 126/*
127s32 127 * checksum the plaintext data and hdrlen bytes of the token header
128make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body, 128 * The checksum is performed over the first 8 bytes of the
129 int body_offset, struct xdr_netobj *cksum) 129 * gss token header and then over the data body
130 */
131u32
132make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
133 struct xdr_buf *body, int body_offset, u8 *cksumkey,
134 struct xdr_netobj *cksumout)
130{ 135{
131 struct hash_desc desc; /* XXX add to ctx? */ 136 struct hash_desc desc;
132 struct scatterlist sg[1]; 137 struct scatterlist sg[1];
133 int err; 138 int err;
139 u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
140 unsigned int checksumlen;
141
142 if (cksumout->len < kctx->gk5e->cksumlength) {
143 dprintk("%s: checksum buffer length, %u, too small for %s\n",
144 __func__, cksumout->len, kctx->gk5e->name);
145 return GSS_S_FAILURE;
146 }
134 147
135 desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC); 148 desc.tfm = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
136 if (IS_ERR(desc.tfm)) 149 if (IS_ERR(desc.tfm))
137 return GSS_S_FAILURE; 150 return GSS_S_FAILURE;
138 cksum->len = crypto_hash_digestsize(desc.tfm);
139 desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; 151 desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
140 152
153 checksumlen = crypto_hash_digestsize(desc.tfm);
154
155 if (cksumkey != NULL) {
156 err = crypto_hash_setkey(desc.tfm, cksumkey,
157 kctx->gk5e->keylength);
158 if (err)
159 goto out;
160 }
161
141 err = crypto_hash_init(&desc); 162 err = crypto_hash_init(&desc);
142 if (err) 163 if (err)
143 goto out; 164 goto out;
@@ -149,8 +170,25 @@ make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body,
149 checksummer, &desc); 170 checksummer, &desc);
150 if (err) 171 if (err)
151 goto out; 172 goto out;
152 err = crypto_hash_final(&desc, cksum->data); 173 err = crypto_hash_final(&desc, checksumdata);
174 if (err)
175 goto out;
153 176
177 switch (kctx->gk5e->ctype) {
178 case CKSUMTYPE_RSA_MD5:
179 err = kctx->gk5e->encrypt(kctx->seq, NULL, checksumdata,
180 checksumdata, checksumlen);
181 if (err)
182 goto out;
183 memcpy(cksumout->data,
184 checksumdata + checksumlen - kctx->gk5e->cksumlength,
185 kctx->gk5e->cksumlength);
186 break;
187 default:
188 BUG();
189 break;
190 }
191 cksumout->len = kctx->gk5e->cksumlength;
154out: 192out:
155 crypto_free_hash(desc.tfm); 193 crypto_free_hash(desc.tfm);
156 return err ? GSS_S_FAILURE : 0; 194 return err ? GSS_S_FAILURE : 0;
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index a66eb706aeb7..6f93f4752be4 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -66,6 +66,7 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
66 .keylength = 8, 66 .keylength = 8,
67 .blocksize = 8, 67 .blocksize = 8,
68 .cksumlength = 8, 68 .cksumlength = 8,
69 .keyed_cksum = 0,
69 }, 70 },
70}; 71};
71 72
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 46c6f44e5c3f..cd512719092b 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -101,6 +101,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
101 void *ptr; 101 void *ptr;
102 s32 now; 102 s32 now;
103 u32 seq_send; 103 u32 seq_send;
104 u8 *cksumkey;
104 105
105 dprintk("RPC: %s\n", __func__); 106 dprintk("RPC: %s\n", __func__);
106 BUG_ON(ctx == NULL); 107 BUG_ON(ctx == NULL);
@@ -109,15 +110,15 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
109 110
110 ptr = setup_token(ctx, token); 111 ptr = setup_token(ctx, token);
111 112
112 if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 8, 113 if (ctx->gk5e->keyed_cksum)
113 text, 0, &md5cksum)) 114 cksumkey = ctx->cksum;
114 return GSS_S_FAILURE; 115 else
116 cksumkey = NULL;
115 117
116 if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, 118 if (make_checksum(ctx, ptr, 8, text, 0, cksumkey, &md5cksum))
117 md5cksum.data, md5cksum.len))
118 return GSS_S_FAILURE; 119 return GSS_S_FAILURE;
119 120
120 memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8); 121 memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
121 122
122 spin_lock(&krb5_seq_lock); 123 spin_lock(&krb5_seq_lock);
123 seq_send = ctx->seq_send++; 124 seq_send = ctx->seq_send++;
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 10ee641a39d0..7515bffddf15 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -84,6 +84,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
84 u32 seqnum; 84 u32 seqnum;
85 unsigned char *ptr = (unsigned char *)read_token->data; 85 unsigned char *ptr = (unsigned char *)read_token->data;
86 int bodysize; 86 int bodysize;
87 u8 *cksumkey;
87 88
88 dprintk("RPC: krb5_read_token\n"); 89 dprintk("RPC: krb5_read_token\n");
89 90
@@ -108,14 +109,16 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
108 if ((ptr[6] != 0xff) || (ptr[7] != 0xff)) 109 if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
109 return GSS_S_DEFECTIVE_TOKEN; 110 return GSS_S_DEFECTIVE_TOKEN;
110 111
111 if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 8, 112 if (ctx->gk5e->keyed_cksum)
112 message_buffer, 0, &md5cksum)) 113 cksumkey = ctx->cksum;
113 return GSS_S_FAILURE; 114 else
115 cksumkey = NULL;
114 116
115 if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16)) 117 if (make_checksum(ctx, ptr, 8, message_buffer, 0,
118 cksumkey, &md5cksum))
116 return GSS_S_FAILURE; 119 return GSS_S_FAILURE;
117 120
118 if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 121 if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
119 ctx->gk5e->cksumlength)) 122 ctx->gk5e->cksumlength))
120 return GSS_S_BAD_SIG; 123 return GSS_S_BAD_SIG;
121 124
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 7188891bcc33..2eb3046a84ea 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -167,6 +167,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
167 int headlen; 167 int headlen;
168 struct page **tmp_pages; 168 struct page **tmp_pages;
169 u32 seq_send; 169 u32 seq_send;
170 u8 *cksumkey;
170 171
171 dprintk("RPC: %s\n", __func__); 172 dprintk("RPC: %s\n", __func__);
172 173
@@ -205,18 +206,20 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
205 206
206 make_confounder(msg_start, blocksize); 207 make_confounder(msg_start, blocksize);
207 208
209 if (kctx->gk5e->keyed_cksum)
210 cksumkey = kctx->cksum;
211 else
212 cksumkey = NULL;
213
208 /* XXXJBF: UGH!: */ 214 /* XXXJBF: UGH!: */
209 tmp_pages = buf->pages; 215 tmp_pages = buf->pages;
210 buf->pages = pages; 216 buf->pages = pages;
211 if (make_checksum((char *)kctx->gk5e->cksum_name, ptr, 8, buf, 217 if (make_checksum(kctx, ptr, 8, buf, offset + headlen - blocksize,
212 offset + headlen - blocksize, &md5cksum)) 218 cksumkey, &md5cksum))
213 return GSS_S_FAILURE; 219 return GSS_S_FAILURE;
214 buf->pages = tmp_pages; 220 buf->pages = tmp_pages;
215 221
216 if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, 222 memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
217 md5cksum.data, md5cksum.len))
218 return GSS_S_FAILURE;
219 memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
220 223
221 spin_lock(&krb5_seq_lock); 224 spin_lock(&krb5_seq_lock);
222 seq_send = kctx->seq_send++; 225 seq_send = kctx->seq_send++;
@@ -252,6 +255,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
252 int data_len; 255 int data_len;
253 int blocksize; 256 int blocksize;
254 int crypt_offset; 257 int crypt_offset;
258 u8 *cksumkey;
255 259
256 dprintk("RPC: gss_unwrap_kerberos\n"); 260 dprintk("RPC: gss_unwrap_kerberos\n");
257 261
@@ -288,15 +292,17 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
288 if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset)) 292 if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset))
289 return GSS_S_DEFECTIVE_TOKEN; 293 return GSS_S_DEFECTIVE_TOKEN;
290 294
291 if (make_checksum((char *)kctx->gk5e->cksum_name, ptr, 8, buf, 295 if (kctx->gk5e->keyed_cksum)
292 crypt_offset, &md5cksum)) 296 cksumkey = kctx->cksum;
293 return GSS_S_FAILURE; 297 else
298 cksumkey = NULL;
294 299
295 if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, 300 if (make_checksum(kctx, ptr, 8, buf, crypt_offset,
296 md5cksum.data, md5cksum.len)) 301 cksumkey, &md5cksum))
297 return GSS_S_FAILURE; 302 return GSS_S_FAILURE;
298 303
299 if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8)) 304 if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
305 kctx->gk5e->cksumlength))
300 return GSS_S_BAD_SIG; 306 return GSS_S_BAD_SIG;
301 307
302 /* it got through unscathed. Make sure the context is unexpired */ 308 /* it got through unscathed. Make sure the context is unexpired */