aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorKevin Coffman <kwc@citi.umich.edu>2010-03-17 13:02:54 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-05-14 15:09:17 -0400
commit47d84807762966c3611c38adecec6ea703ddda7a (patch)
treeac67fb9e29aa03e7eba58adae29e8db05fd35537 /net/sunrpc
parent4891f2d008e4343eedea39ba1fe74864f1d32be0 (diff)
gss_krb5: handle new context format from gssd
For encryption types other than DES, gssd sends down context information in a new format. This new format includes the information needed to support the new Kerberos GSS-API tokens defined in rfc4121. 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>
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_keys.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c237
2 files changed, 237 insertions, 2 deletions
diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c
index 832ce901bf68..253b4149584a 100644
--- a/net/sunrpc/auth_gss/gss_krb5_keys.c
+++ b/net/sunrpc/auth_gss/gss_krb5_keys.c
@@ -147,7 +147,7 @@ static void krb5_nfold(u32 inbits, const u8 *in,
147 * Taken from MIT Kerberos and modified. 147 * Taken from MIT Kerberos and modified.
148 */ 148 */
149 149
150u32 krb5_derive_key(struct gss_krb5_enctype *gk5e, 150u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e,
151 const struct xdr_netobj *inkey, 151 const struct xdr_netobj *inkey,
152 struct xdr_netobj *outkey, 152 struct xdr_netobj *outkey,
153 const struct xdr_netobj *in_constant) 153 const struct xdr_netobj *in_constant)
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index fdf0eb2057ab..8b612e733563 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -48,6 +48,8 @@
48# define RPCDBG_FACILITY RPCDBG_AUTH 48# define RPCDBG_FACILITY RPCDBG_AUTH
49#endif 49#endif
50 50
51static struct gss_api_mech gss_kerberos_mech; /* forward declaration */
52
51static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { 53static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
52 /* 54 /*
53 * DES (All DES enctypes are mapped to the same gss functionality) 55 * DES (All DES enctypes are mapped to the same gss functionality)
@@ -247,6 +249,237 @@ out_err:
247 return PTR_ERR(p); 249 return PTR_ERR(p);
248} 250}
249 251
252struct crypto_blkcipher *
253context_v2_alloc_cipher(struct krb5_ctx *ctx, u8 *key)
254{
255 struct crypto_blkcipher *cp;
256
257 cp = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name,
258 0, CRYPTO_ALG_ASYNC);
259 if (IS_ERR(cp)) {
260 dprintk("gss_kerberos_mech: unable to initialize "
261 "crypto algorithm %s\n", ctx->gk5e->encrypt_name);
262 return NULL;
263 }
264 if (crypto_blkcipher_setkey(cp, key, ctx->gk5e->keylength)) {
265 dprintk("gss_kerberos_mech: error setting key for "
266 "crypto algorithm %s\n", ctx->gk5e->encrypt_name);
267 crypto_free_blkcipher(cp);
268 return NULL;
269 }
270 return cp;
271}
272
273static inline void
274set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed)
275{
276 cdata[0] = (usage>>24)&0xff;
277 cdata[1] = (usage>>16)&0xff;
278 cdata[2] = (usage>>8)&0xff;
279 cdata[3] = usage&0xff;
280 cdata[4] = seed;
281}
282
283static int
284context_derive_keys_des3(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
285{
286 struct xdr_netobj c, keyin, keyout;
287 u8 cdata[GSS_KRB5_K5CLENGTH];
288 u32 err;
289
290 c.len = GSS_KRB5_K5CLENGTH;
291 c.data = cdata;
292
293 keyin.data = rawkey;
294 keyin.len = keylen;
295 keyout.len = keylen;
296
297 /* seq uses the raw key */
298 ctx->seq = context_v2_alloc_cipher(ctx, rawkey);
299 if (ctx->seq == NULL)
300 goto out_err;
301
302 ctx->enc = context_v2_alloc_cipher(ctx, rawkey);
303 if (ctx->enc == NULL)
304 goto out_free_seq;
305
306 /* derive cksum */
307 set_cdata(cdata, KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM);
308 keyout.data = ctx->cksum;
309 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
310 if (err) {
311 dprintk("%s: Error %d deriving cksum key\n",
312 __func__, err);
313 goto out_free_enc;
314 }
315
316 return 0;
317
318out_free_enc:
319 crypto_free_blkcipher(ctx->enc);
320out_free_seq:
321 crypto_free_blkcipher(ctx->seq);
322out_err:
323 return -EINVAL;
324}
325
326static int
327context_derive_keys_new(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
328{
329 struct xdr_netobj c, keyin, keyout;
330 u8 cdata[GSS_KRB5_K5CLENGTH];
331 u32 err;
332
333 c.len = GSS_KRB5_K5CLENGTH;
334 c.data = cdata;
335
336 keyin.data = rawkey;
337 keyin.len = keylen;
338 keyout.len = keylen;
339
340 /* initiator seal encryption */
341 set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION);
342 keyout.data = ctx->initiator_seal;
343 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
344 if (err) {
345 dprintk("%s: Error %d deriving initiator_seal key\n",
346 __func__, err);
347 goto out_err;
348 }
349 ctx->initiator_enc = context_v2_alloc_cipher(ctx, ctx->initiator_seal);
350 if (ctx->initiator_enc == NULL)
351 goto out_err;
352
353 /* acceptor seal encryption */
354 set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_ENCRYPTION);
355 keyout.data = ctx->acceptor_seal;
356 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
357 if (err) {
358 dprintk("%s: Error %d deriving acceptor_seal key\n",
359 __func__, err);
360 goto out_free_initiator_enc;
361 }
362 ctx->acceptor_enc = context_v2_alloc_cipher(ctx, ctx->acceptor_seal);
363 if (ctx->acceptor_enc == NULL)
364 goto out_free_initiator_enc;
365
366 /* initiator sign checksum */
367 set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM);
368 keyout.data = ctx->initiator_sign;
369 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
370 if (err) {
371 dprintk("%s: Error %d deriving initiator_sign key\n",
372 __func__, err);
373 goto out_free_acceptor_enc;
374 }
375
376 /* acceptor sign checksum */
377 set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM);
378 keyout.data = ctx->acceptor_sign;
379 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
380 if (err) {
381 dprintk("%s: Error %d deriving acceptor_sign key\n",
382 __func__, err);
383 goto out_free_acceptor_enc;
384 }
385
386 /* initiator seal integrity */
387 set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY);
388 keyout.data = ctx->initiator_integ;
389 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
390 if (err) {
391 dprintk("%s: Error %d deriving initiator_integ key\n",
392 __func__, err);
393 goto out_free_acceptor_enc;
394 }
395
396 /* acceptor seal integrity */
397 set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_INTEGRITY);
398 keyout.data = ctx->acceptor_integ;
399 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
400 if (err) {
401 dprintk("%s: Error %d deriving acceptor_integ key\n",
402 __func__, err);
403 goto out_free_acceptor_enc;
404 }
405
406 return 0;
407
408out_free_acceptor_enc:
409 crypto_free_blkcipher(ctx->acceptor_enc);
410out_free_initiator_enc:
411 crypto_free_blkcipher(ctx->initiator_enc);
412out_err:
413 return -EINVAL;
414}
415
416static int
417gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx)
418{
419 u8 rawkey[GSS_KRB5_MAX_KEYLEN];
420 int keylen;
421
422 p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags));
423 if (IS_ERR(p))
424 goto out_err;
425 ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR;
426
427 p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
428 if (IS_ERR(p))
429 goto out_err;
430 p = simple_get_bytes(p, end, &ctx->seq_send64, sizeof(ctx->seq_send64));
431 if (IS_ERR(p))
432 goto out_err;
433 /* set seq_send for use by "older" enctypes */
434 ctx->seq_send = ctx->seq_send64;
435 if (ctx->seq_send64 != ctx->seq_send) {
436 dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__,
437 (long unsigned)ctx->seq_send64, ctx->seq_send);
438 goto out_err;
439 }
440 p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype));
441 if (IS_ERR(p))
442 goto out_err;
443 ctx->gk5e = get_gss_krb5_enctype(ctx->enctype);
444 if (ctx->gk5e == NULL) {
445 dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n",
446 ctx->enctype);
447 p = ERR_PTR(-EINVAL);
448 goto out_err;
449 }
450 keylen = ctx->gk5e->keylength;
451
452 p = simple_get_bytes(p, end, rawkey, keylen);
453 if (IS_ERR(p))
454 goto out_err;
455
456 if (p != end) {
457 p = ERR_PTR(-EINVAL);
458 goto out_err;
459 }
460
461 ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data,
462 gss_kerberos_mech.gm_oid.len, GFP_KERNEL);
463 if (unlikely(ctx->mech_used.data == NULL)) {
464 p = ERR_PTR(-ENOMEM);
465 goto out_err;
466 }
467 ctx->mech_used.len = gss_kerberos_mech.gm_oid.len;
468
469 switch (ctx->enctype) {
470 case ENCTYPE_DES3_CBC_RAW:
471 return context_derive_keys_des3(ctx, rawkey, keylen);
472 case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
473 case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
474 return context_derive_keys_new(ctx, rawkey, keylen);
475 default:
476 return -EINVAL;
477 }
478
479out_err:
480 return PTR_ERR(p);
481}
482
250static int 483static int
251gss_import_sec_context_kerberos(const void *p, size_t len, 484gss_import_sec_context_kerberos(const void *p, size_t len,
252 struct gss_ctx *ctx_id) 485 struct gss_ctx *ctx_id)
@@ -262,7 +495,7 @@ gss_import_sec_context_kerberos(const void *p, size_t len,
262 if (len == 85) 495 if (len == 85)
263 ret = gss_import_v1_context(p, end, ctx); 496 ret = gss_import_v1_context(p, end, ctx);
264 else 497 else
265 ret = -EINVAL; 498 ret = gss_import_v2_context(p, end, ctx);
266 499
267 if (ret == 0) 500 if (ret == 0)
268 ctx_id->internal_ctx_id = ctx; 501 ctx_id->internal_ctx_id = ctx;
@@ -279,6 +512,8 @@ gss_delete_sec_context_kerberos(void *internal_ctx) {
279 512
280 crypto_free_blkcipher(kctx->seq); 513 crypto_free_blkcipher(kctx->seq);
281 crypto_free_blkcipher(kctx->enc); 514 crypto_free_blkcipher(kctx->enc);
515 crypto_free_blkcipher(kctx->acceptor_enc);
516 crypto_free_blkcipher(kctx->initiator_enc);
282 kfree(kctx->mech_used.data); 517 kfree(kctx->mech_used.data);
283 kfree(kctx); 518 kfree(kctx);
284} 519}