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 | |
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>
-rw-r--r-- | include/linux/sunrpc/gss_krb5.h | 23 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_keys.c | 2 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_mech.c | 237 |
3 files changed, 258 insertions, 4 deletions
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index d31ba0304d18..04d5279f17df 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h | |||
@@ -72,21 +72,36 @@ struct gss_krb5_enctype { | |||
72 | u32 (*decrypt) (struct crypto_blkcipher *tfm, | 72 | u32 (*decrypt) (struct crypto_blkcipher *tfm, |
73 | void *iv, void *in, void *out, | 73 | void *iv, void *in, void *out, |
74 | int length); /* decryption function */ | 74 | int length); /* decryption function */ |
75 | u32 (*mk_key) (struct gss_krb5_enctype *gk5e, | 75 | u32 (*mk_key) (const struct gss_krb5_enctype *gk5e, |
76 | struct xdr_netobj *in, | 76 | struct xdr_netobj *in, |
77 | struct xdr_netobj *out); /* complete key generation */ | 77 | struct xdr_netobj *out); /* complete key generation */ |
78 | }; | 78 | }; |
79 | 79 | ||
80 | /* krb5_ctx flags definitions */ | ||
81 | #define KRB5_CTX_FLAG_INITIATOR 0x00000001 | ||
82 | #define KRB5_CTX_FLAG_CFX 0x00000002 | ||
83 | #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | ||
84 | |||
80 | struct krb5_ctx { | 85 | struct krb5_ctx { |
81 | int initiate; /* 1 = initiating, 0 = accepting */ | 86 | int initiate; /* 1 = initiating, 0 = accepting */ |
82 | u32 enctype; | 87 | u32 enctype; |
88 | u32 flags; | ||
83 | const struct gss_krb5_enctype *gk5e; /* enctype-specific info */ | 89 | const struct gss_krb5_enctype *gk5e; /* enctype-specific info */ |
84 | struct crypto_blkcipher *enc; | 90 | struct crypto_blkcipher *enc; |
85 | struct crypto_blkcipher *seq; | 91 | struct crypto_blkcipher *seq; |
92 | struct crypto_blkcipher *acceptor_enc; | ||
93 | struct crypto_blkcipher *initiator_enc; | ||
86 | u8 cksum[GSS_KRB5_MAX_KEYLEN]; | 94 | u8 cksum[GSS_KRB5_MAX_KEYLEN]; |
87 | s32 endtime; | 95 | s32 endtime; |
88 | u32 seq_send; | 96 | u32 seq_send; |
97 | u64 seq_send64; | ||
89 | struct xdr_netobj mech_used; | 98 | struct xdr_netobj mech_used; |
99 | u8 initiator_sign[GSS_KRB5_MAX_KEYLEN]; | ||
100 | u8 acceptor_sign[GSS_KRB5_MAX_KEYLEN]; | ||
101 | u8 initiator_seal[GSS_KRB5_MAX_KEYLEN]; | ||
102 | u8 acceptor_seal[GSS_KRB5_MAX_KEYLEN]; | ||
103 | u8 initiator_integ[GSS_KRB5_MAX_KEYLEN]; | ||
104 | u8 acceptor_integ[GSS_KRB5_MAX_KEYLEN]; | ||
90 | }; | 105 | }; |
91 | 106 | ||
92 | extern spinlock_t krb5_seq_lock; | 107 | extern spinlock_t krb5_seq_lock; |
@@ -151,6 +166,10 @@ enum seal_alg { | |||
151 | #define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */ | 166 | #define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */ |
152 | #define ENCTYPE_DES_HMAC_SHA1 0x0008 | 167 | #define ENCTYPE_DES_HMAC_SHA1 0x0008 |
153 | #define ENCTYPE_DES3_CBC_SHA1 0x0010 | 168 | #define ENCTYPE_DES3_CBC_SHA1 0x0010 |
169 | #define ENCTYPE_AES128_CTS_HMAC_SHA1_96 0x0011 | ||
170 | #define ENCTYPE_AES256_CTS_HMAC_SHA1_96 0x0012 | ||
171 | #define ENCTYPE_ARCFOUR_HMAC 0x0017 | ||
172 | #define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018 | ||
154 | #define ENCTYPE_UNKNOWN 0x01ff | 173 | #define ENCTYPE_UNKNOWN 0x01ff |
155 | 174 | ||
156 | /* | 175 | /* |
@@ -238,7 +257,7 @@ int | |||
238 | xdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen); | 257 | xdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen); |
239 | 258 | ||
240 | u32 | 259 | u32 |
241 | krb5_derive_key(struct gss_krb5_enctype *gk5e, | 260 | krb5_derive_key(const struct gss_krb5_enctype *gk5e, |
242 | const struct xdr_netobj *inkey, | 261 | const struct xdr_netobj *inkey, |
243 | struct xdr_netobj *outkey, | 262 | struct xdr_netobj *outkey, |
244 | const struct xdr_netobj *in_constant); | 263 | const struct xdr_netobj *in_constant); |
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 | } |