diff options
author | Kevin Coffman <kwc@citi.umich.edu> | 2010-03-17 13:02:54 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-05-14 15:09:17 -0400 |
commit | 47d84807762966c3611c38adecec6ea703ddda7a (patch) | |
tree | ac67fb9e29aa03e7eba58adae29e8db05fd35537 /net/sunrpc | |
parent | 4891f2d008e4343eedea39ba1fe74864f1d32be0 (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.c | 2 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_mech.c | 237 |
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 | ||
150 | u32 krb5_derive_key(struct gss_krb5_enctype *gk5e, | 150 | u32 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 | ||
51 | static struct gss_api_mech gss_kerberos_mech; /* forward declaration */ | ||
52 | |||
51 | static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { | 53 | static 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 | ||
252 | struct crypto_blkcipher * | ||
253 | context_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 | |||
273 | static inline void | ||
274 | set_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 | |||
283 | static int | ||
284 | context_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 | |||
318 | out_free_enc: | ||
319 | crypto_free_blkcipher(ctx->enc); | ||
320 | out_free_seq: | ||
321 | crypto_free_blkcipher(ctx->seq); | ||
322 | out_err: | ||
323 | return -EINVAL; | ||
324 | } | ||
325 | |||
326 | static int | ||
327 | context_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 | |||
408 | out_free_acceptor_enc: | ||
409 | crypto_free_blkcipher(ctx->acceptor_enc); | ||
410 | out_free_initiator_enc: | ||
411 | crypto_free_blkcipher(ctx->initiator_enc); | ||
412 | out_err: | ||
413 | return -EINVAL; | ||
414 | } | ||
415 | |||
416 | static int | ||
417 | gss_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 | |||
479 | out_err: | ||
480 | return PTR_ERR(p); | ||
481 | } | ||
482 | |||
250 | static int | 483 | static int |
251 | gss_import_sec_context_kerberos(const void *p, size_t len, | 484 | gss_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 | } |