xref: /linux/net/sunrpc/auth_gss/gss_krb5_mech.c (revision 4b132aacb0768ac1e652cf517097ea6f237214b9)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  *  linux/net/sunrpc/gss_krb5_mech.c
4  *
5  *  Copyright (c) 2001-2008 The Regents of the University of Michigan.
6  *  All rights reserved.
7  *
8  *  Andy Adamson <andros@umich.edu>
9  *  J. Bruce Fields <bfields@umich.edu>
10  */
11 
12 #include <crypto/hash.h>
13 #include <crypto/skcipher.h>
14 #include <linux/err.h>
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/types.h>
18 #include <linux/slab.h>
19 #include <linux/sunrpc/auth.h>
20 #include <linux/sunrpc/gss_krb5.h>
21 #include <linux/sunrpc/xdr.h>
22 #include <kunit/visibility.h>
23 
24 #include "auth_gss_internal.h"
25 #include "gss_krb5_internal.h"
26 
27 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
28 # define RPCDBG_FACILITY	RPCDBG_AUTH
29 #endif
30 
31 static struct gss_api_mech gss_kerberos_mech;
32 
33 static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
34 #if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1)
35 	/*
36 	 * AES-128 with SHA-1 (RFC 3962)
37 	 */
38 	{
39 	  .etype = ENCTYPE_AES128_CTS_HMAC_SHA1_96,
40 	  .ctype = CKSUMTYPE_HMAC_SHA1_96_AES128,
41 	  .name = "aes128-cts",
42 	  .encrypt_name = "cts(cbc(aes))",
43 	  .aux_cipher = "cbc(aes)",
44 	  .cksum_name = "hmac(sha1)",
45 	  .derive_key = krb5_derive_key_v2,
46 	  .encrypt = gss_krb5_aes_encrypt,
47 	  .decrypt = gss_krb5_aes_decrypt,
48 
49 	  .get_mic = gss_krb5_get_mic_v2,
50 	  .verify_mic = gss_krb5_verify_mic_v2,
51 	  .wrap = gss_krb5_wrap_v2,
52 	  .unwrap = gss_krb5_unwrap_v2,
53 
54 	  .signalg = -1,
55 	  .sealalg = -1,
56 	  .keybytes = 16,
57 	  .keylength = BITS2OCTETS(128),
58 	  .Kc_length = BITS2OCTETS(128),
59 	  .Ke_length = BITS2OCTETS(128),
60 	  .Ki_length = BITS2OCTETS(128),
61 	  .cksumlength = BITS2OCTETS(96),
62 	  .keyed_cksum = 1,
63 	},
64 	/*
65 	 * AES-256 with SHA-1 (RFC 3962)
66 	 */
67 	{
68 	  .etype = ENCTYPE_AES256_CTS_HMAC_SHA1_96,
69 	  .ctype = CKSUMTYPE_HMAC_SHA1_96_AES256,
70 	  .name = "aes256-cts",
71 	  .encrypt_name = "cts(cbc(aes))",
72 	  .aux_cipher = "cbc(aes)",
73 	  .cksum_name = "hmac(sha1)",
74 	  .derive_key = krb5_derive_key_v2,
75 	  .encrypt = gss_krb5_aes_encrypt,
76 	  .decrypt = gss_krb5_aes_decrypt,
77 
78 	  .get_mic = gss_krb5_get_mic_v2,
79 	  .verify_mic = gss_krb5_verify_mic_v2,
80 	  .wrap = gss_krb5_wrap_v2,
81 	  .unwrap = gss_krb5_unwrap_v2,
82 
83 	  .signalg = -1,
84 	  .sealalg = -1,
85 	  .keybytes = 32,
86 	  .keylength = BITS2OCTETS(256),
87 	  .Kc_length = BITS2OCTETS(256),
88 	  .Ke_length = BITS2OCTETS(256),
89 	  .Ki_length = BITS2OCTETS(256),
90 	  .cksumlength = BITS2OCTETS(96),
91 	  .keyed_cksum = 1,
92 	},
93 #endif
94 
95 #if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA)
96 	/*
97 	 * Camellia-128 with CMAC (RFC 6803)
98 	 */
99 	{
100 		.etype		= ENCTYPE_CAMELLIA128_CTS_CMAC,
101 		.ctype		= CKSUMTYPE_CMAC_CAMELLIA128,
102 		.name		= "camellia128-cts-cmac",
103 		.encrypt_name	= "cts(cbc(camellia))",
104 		.aux_cipher	= "cbc(camellia)",
105 		.cksum_name	= "cmac(camellia)",
106 		.cksumlength	= BITS2OCTETS(128),
107 		.keyed_cksum	= 1,
108 		.keylength	= BITS2OCTETS(128),
109 		.Kc_length	= BITS2OCTETS(128),
110 		.Ke_length	= BITS2OCTETS(128),
111 		.Ki_length	= BITS2OCTETS(128),
112 
113 		.derive_key	= krb5_kdf_feedback_cmac,
114 		.encrypt	= gss_krb5_aes_encrypt,
115 		.decrypt	= gss_krb5_aes_decrypt,
116 
117 		.get_mic	= gss_krb5_get_mic_v2,
118 		.verify_mic	= gss_krb5_verify_mic_v2,
119 		.wrap		= gss_krb5_wrap_v2,
120 		.unwrap		= gss_krb5_unwrap_v2,
121 	},
122 	/*
123 	 * Camellia-256 with CMAC (RFC 6803)
124 	 */
125 	{
126 		.etype		= ENCTYPE_CAMELLIA256_CTS_CMAC,
127 		.ctype		= CKSUMTYPE_CMAC_CAMELLIA256,
128 		.name		= "camellia256-cts-cmac",
129 		.encrypt_name	= "cts(cbc(camellia))",
130 		.aux_cipher	= "cbc(camellia)",
131 		.cksum_name	= "cmac(camellia)",
132 		.cksumlength	= BITS2OCTETS(128),
133 		.keyed_cksum	= 1,
134 		.keylength	= BITS2OCTETS(256),
135 		.Kc_length	= BITS2OCTETS(256),
136 		.Ke_length	= BITS2OCTETS(256),
137 		.Ki_length	= BITS2OCTETS(256),
138 
139 		.derive_key	= krb5_kdf_feedback_cmac,
140 		.encrypt	= gss_krb5_aes_encrypt,
141 		.decrypt	= gss_krb5_aes_decrypt,
142 
143 		.get_mic	= gss_krb5_get_mic_v2,
144 		.verify_mic	= gss_krb5_verify_mic_v2,
145 		.wrap		= gss_krb5_wrap_v2,
146 		.unwrap		= gss_krb5_unwrap_v2,
147 	},
148 #endif
149 
150 #if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2)
151 	/*
152 	 * AES-128 with SHA-256 (RFC 8009)
153 	 */
154 	{
155 		.etype		= ENCTYPE_AES128_CTS_HMAC_SHA256_128,
156 		.ctype		= CKSUMTYPE_HMAC_SHA256_128_AES128,
157 		.name		= "aes128-cts-hmac-sha256-128",
158 		.encrypt_name	= "cts(cbc(aes))",
159 		.aux_cipher	= "cbc(aes)",
160 		.cksum_name	= "hmac(sha256)",
161 		.cksumlength	= BITS2OCTETS(128),
162 		.keyed_cksum	= 1,
163 		.keylength	= BITS2OCTETS(128),
164 		.Kc_length	= BITS2OCTETS(128),
165 		.Ke_length	= BITS2OCTETS(128),
166 		.Ki_length	= BITS2OCTETS(128),
167 
168 		.derive_key	= krb5_kdf_hmac_sha2,
169 		.encrypt	= krb5_etm_encrypt,
170 		.decrypt	= krb5_etm_decrypt,
171 
172 		.get_mic	= gss_krb5_get_mic_v2,
173 		.verify_mic	= gss_krb5_verify_mic_v2,
174 		.wrap		= gss_krb5_wrap_v2,
175 		.unwrap		= gss_krb5_unwrap_v2,
176 	},
177 	/*
178 	 * AES-256 with SHA-384 (RFC 8009)
179 	 */
180 	{
181 		.etype		= ENCTYPE_AES256_CTS_HMAC_SHA384_192,
182 		.ctype		= CKSUMTYPE_HMAC_SHA384_192_AES256,
183 		.name		= "aes256-cts-hmac-sha384-192",
184 		.encrypt_name	= "cts(cbc(aes))",
185 		.aux_cipher	= "cbc(aes)",
186 		.cksum_name	= "hmac(sha384)",
187 		.cksumlength	= BITS2OCTETS(192),
188 		.keyed_cksum	= 1,
189 		.keylength	= BITS2OCTETS(256),
190 		.Kc_length	= BITS2OCTETS(192),
191 		.Ke_length	= BITS2OCTETS(256),
192 		.Ki_length	= BITS2OCTETS(192),
193 
194 		.derive_key	= krb5_kdf_hmac_sha2,
195 		.encrypt	= krb5_etm_encrypt,
196 		.decrypt	= krb5_etm_decrypt,
197 
198 		.get_mic	= gss_krb5_get_mic_v2,
199 		.verify_mic	= gss_krb5_verify_mic_v2,
200 		.wrap		= gss_krb5_wrap_v2,
201 		.unwrap		= gss_krb5_unwrap_v2,
202 	},
203 #endif
204 };
205 
206 /*
207  * The list of advertised enctypes is specified in order of most
208  * preferred to least.
209  */
210 static char gss_krb5_enctype_priority_list[64];
211 
212 static void gss_krb5_prepare_enctype_priority_list(void)
213 {
214 	static const u32 gss_krb5_enctypes[] = {
215 #if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2)
216 		ENCTYPE_AES256_CTS_HMAC_SHA384_192,
217 		ENCTYPE_AES128_CTS_HMAC_SHA256_128,
218 #endif
219 #if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA)
220 		ENCTYPE_CAMELLIA256_CTS_CMAC,
221 		ENCTYPE_CAMELLIA128_CTS_CMAC,
222 #endif
223 #if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1)
224 		ENCTYPE_AES256_CTS_HMAC_SHA1_96,
225 		ENCTYPE_AES128_CTS_HMAC_SHA1_96,
226 #endif
227 	};
228 	size_t total, i;
229 	char buf[16];
230 	char *sep;
231 	int n;
232 
233 	sep = "";
234 	gss_krb5_enctype_priority_list[0] = '\0';
235 	for (total = 0, i = 0; i < ARRAY_SIZE(gss_krb5_enctypes); i++) {
236 		n = sprintf(buf, "%s%u", sep, gss_krb5_enctypes[i]);
237 		if (n < 0)
238 			break;
239 		if (total + n >= sizeof(gss_krb5_enctype_priority_list))
240 			break;
241 		strcat(gss_krb5_enctype_priority_list, buf);
242 		sep = ",";
243 		total += n;
244 	}
245 }
246 
247 /**
248  * gss_krb5_lookup_enctype - Retrieve profile information for a given enctype
249  * @etype: ENCTYPE value
250  *
251  * Returns a pointer to a gss_krb5_enctype structure, or NULL if no
252  * matching etype is found.
253  */
254 VISIBLE_IF_KUNIT
255 const struct gss_krb5_enctype *gss_krb5_lookup_enctype(u32 etype)
256 {
257 	size_t i;
258 
259 	for (i = 0; i < ARRAY_SIZE(supported_gss_krb5_enctypes); i++)
260 		if (supported_gss_krb5_enctypes[i].etype == etype)
261 			return &supported_gss_krb5_enctypes[i];
262 	return NULL;
263 }
264 EXPORT_SYMBOL_IF_KUNIT(gss_krb5_lookup_enctype);
265 
266 static struct crypto_sync_skcipher *
267 gss_krb5_alloc_cipher_v2(const char *cname, const struct xdr_netobj *key)
268 {
269 	struct crypto_sync_skcipher *tfm;
270 
271 	tfm = crypto_alloc_sync_skcipher(cname, 0, 0);
272 	if (IS_ERR(tfm))
273 		return NULL;
274 	if (crypto_sync_skcipher_setkey(tfm, key->data, key->len)) {
275 		crypto_free_sync_skcipher(tfm);
276 		return NULL;
277 	}
278 	return tfm;
279 }
280 
281 static struct crypto_ahash *
282 gss_krb5_alloc_hash_v2(struct krb5_ctx *kctx, const struct xdr_netobj *key)
283 {
284 	struct crypto_ahash *tfm;
285 
286 	tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
287 	if (IS_ERR(tfm))
288 		return NULL;
289 	if (crypto_ahash_setkey(tfm, key->data, key->len)) {
290 		crypto_free_ahash(tfm);
291 		return NULL;
292 	}
293 	return tfm;
294 }
295 
296 static int
297 gss_krb5_import_ctx_v2(struct krb5_ctx *ctx, gfp_t gfp_mask)
298 {
299 	struct xdr_netobj keyin = {
300 		.len	= ctx->gk5e->keylength,
301 		.data	= ctx->Ksess,
302 	};
303 	struct xdr_netobj keyout;
304 	int ret = -EINVAL;
305 
306 	keyout.data = kmalloc(GSS_KRB5_MAX_KEYLEN, gfp_mask);
307 	if (!keyout.data)
308 		return -ENOMEM;
309 
310 	/* initiator seal encryption */
311 	keyout.len = ctx->gk5e->Ke_length;
312 	if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_INITIATOR_SEAL,
313 			    KEY_USAGE_SEED_ENCRYPTION, gfp_mask))
314 		goto out;
315 	ctx->initiator_enc = gss_krb5_alloc_cipher_v2(ctx->gk5e->encrypt_name,
316 						      &keyout);
317 	if (ctx->initiator_enc == NULL)
318 		goto out;
319 	if (ctx->gk5e->aux_cipher) {
320 		ctx->initiator_enc_aux =
321 			gss_krb5_alloc_cipher_v2(ctx->gk5e->aux_cipher,
322 						 &keyout);
323 		if (ctx->initiator_enc_aux == NULL)
324 			goto out_free;
325 	}
326 
327 	/* acceptor seal encryption */
328 	if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_ACCEPTOR_SEAL,
329 			    KEY_USAGE_SEED_ENCRYPTION, gfp_mask))
330 		goto out_free;
331 	ctx->acceptor_enc = gss_krb5_alloc_cipher_v2(ctx->gk5e->encrypt_name,
332 						     &keyout);
333 	if (ctx->acceptor_enc == NULL)
334 		goto out_free;
335 	if (ctx->gk5e->aux_cipher) {
336 		ctx->acceptor_enc_aux =
337 			gss_krb5_alloc_cipher_v2(ctx->gk5e->aux_cipher,
338 						 &keyout);
339 		if (ctx->acceptor_enc_aux == NULL)
340 			goto out_free;
341 	}
342 
343 	/* initiator sign checksum */
344 	keyout.len = ctx->gk5e->Kc_length;
345 	if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_INITIATOR_SIGN,
346 			    KEY_USAGE_SEED_CHECKSUM, gfp_mask))
347 		goto out_free;
348 	ctx->initiator_sign = gss_krb5_alloc_hash_v2(ctx, &keyout);
349 	if (ctx->initiator_sign == NULL)
350 		goto out_free;
351 
352 	/* acceptor sign checksum */
353 	if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_ACCEPTOR_SIGN,
354 			    KEY_USAGE_SEED_CHECKSUM, gfp_mask))
355 		goto out_free;
356 	ctx->acceptor_sign = gss_krb5_alloc_hash_v2(ctx, &keyout);
357 	if (ctx->acceptor_sign == NULL)
358 		goto out_free;
359 
360 	/* initiator seal integrity */
361 	keyout.len = ctx->gk5e->Ki_length;
362 	if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_INITIATOR_SEAL,
363 			    KEY_USAGE_SEED_INTEGRITY, gfp_mask))
364 		goto out_free;
365 	ctx->initiator_integ = gss_krb5_alloc_hash_v2(ctx, &keyout);
366 	if (ctx->initiator_integ == NULL)
367 		goto out_free;
368 
369 	/* acceptor seal integrity */
370 	if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_ACCEPTOR_SEAL,
371 			    KEY_USAGE_SEED_INTEGRITY, gfp_mask))
372 		goto out_free;
373 	ctx->acceptor_integ = gss_krb5_alloc_hash_v2(ctx, &keyout);
374 	if (ctx->acceptor_integ == NULL)
375 		goto out_free;
376 
377 	ret = 0;
378 out:
379 	kfree_sensitive(keyout.data);
380 	return ret;
381 
382 out_free:
383 	crypto_free_ahash(ctx->acceptor_integ);
384 	crypto_free_ahash(ctx->initiator_integ);
385 	crypto_free_ahash(ctx->acceptor_sign);
386 	crypto_free_ahash(ctx->initiator_sign);
387 	crypto_free_sync_skcipher(ctx->acceptor_enc_aux);
388 	crypto_free_sync_skcipher(ctx->acceptor_enc);
389 	crypto_free_sync_skcipher(ctx->initiator_enc_aux);
390 	crypto_free_sync_skcipher(ctx->initiator_enc);
391 	goto out;
392 }
393 
394 static int
395 gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,
396 		gfp_t gfp_mask)
397 {
398 	u64 seq_send64;
399 	int keylen;
400 	u32 time32;
401 	int ret;
402 
403 	p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags));
404 	if (IS_ERR(p))
405 		goto out_err;
406 	ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR;
407 
408 	p = simple_get_bytes(p, end, &time32, sizeof(time32));
409 	if (IS_ERR(p))
410 		goto out_err;
411 	/* unsigned 32-bit time overflows in year 2106 */
412 	ctx->endtime = (time64_t)time32;
413 	p = simple_get_bytes(p, end, &seq_send64, sizeof(seq_send64));
414 	if (IS_ERR(p))
415 		goto out_err;
416 	atomic64_set(&ctx->seq_send64, seq_send64);
417 	/* set seq_send for use by "older" enctypes */
418 	atomic_set(&ctx->seq_send, seq_send64);
419 	if (seq_send64 != atomic_read(&ctx->seq_send)) {
420 		dprintk("%s: seq_send64 %llx, seq_send %x overflow?\n", __func__,
421 			seq_send64, atomic_read(&ctx->seq_send));
422 		p = ERR_PTR(-EINVAL);
423 		goto out_err;
424 	}
425 	p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype));
426 	if (IS_ERR(p))
427 		goto out_err;
428 	ctx->gk5e = gss_krb5_lookup_enctype(ctx->enctype);
429 	if (ctx->gk5e == NULL) {
430 		dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n",
431 			ctx->enctype);
432 		p = ERR_PTR(-EINVAL);
433 		goto out_err;
434 	}
435 	keylen = ctx->gk5e->keylength;
436 
437 	p = simple_get_bytes(p, end, ctx->Ksess, keylen);
438 	if (IS_ERR(p))
439 		goto out_err;
440 
441 	if (p != end) {
442 		p = ERR_PTR(-EINVAL);
443 		goto out_err;
444 	}
445 
446 	ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data,
447 				      gss_kerberos_mech.gm_oid.len, gfp_mask);
448 	if (unlikely(ctx->mech_used.data == NULL)) {
449 		p = ERR_PTR(-ENOMEM);
450 		goto out_err;
451 	}
452 	ctx->mech_used.len = gss_kerberos_mech.gm_oid.len;
453 
454 	ret = gss_krb5_import_ctx_v2(ctx, gfp_mask);
455 	if (ret) {
456 		p = ERR_PTR(ret);
457 		goto out_free;
458 	}
459 
460 	return 0;
461 
462 out_free:
463 	kfree(ctx->mech_used.data);
464 out_err:
465 	return PTR_ERR(p);
466 }
467 
468 static int
469 gss_krb5_import_sec_context(const void *p, size_t len, struct gss_ctx *ctx_id,
470 			    time64_t *endtime, gfp_t gfp_mask)
471 {
472 	const void *end = (const void *)((const char *)p + len);
473 	struct  krb5_ctx *ctx;
474 	int ret;
475 
476 	ctx = kzalloc(sizeof(*ctx), gfp_mask);
477 	if (ctx == NULL)
478 		return -ENOMEM;
479 
480 	ret = gss_import_v2_context(p, end, ctx, gfp_mask);
481 	memzero_explicit(&ctx->Ksess, sizeof(ctx->Ksess));
482 	if (ret) {
483 		kfree(ctx);
484 		return ret;
485 	}
486 
487 	ctx_id->internal_ctx_id = ctx;
488 	if (endtime)
489 		*endtime = ctx->endtime;
490 	return 0;
491 }
492 
493 static void
494 gss_krb5_delete_sec_context(void *internal_ctx)
495 {
496 	struct krb5_ctx *kctx = internal_ctx;
497 
498 	crypto_free_sync_skcipher(kctx->seq);
499 	crypto_free_sync_skcipher(kctx->enc);
500 	crypto_free_sync_skcipher(kctx->acceptor_enc);
501 	crypto_free_sync_skcipher(kctx->initiator_enc);
502 	crypto_free_sync_skcipher(kctx->acceptor_enc_aux);
503 	crypto_free_sync_skcipher(kctx->initiator_enc_aux);
504 	crypto_free_ahash(kctx->acceptor_sign);
505 	crypto_free_ahash(kctx->initiator_sign);
506 	crypto_free_ahash(kctx->acceptor_integ);
507 	crypto_free_ahash(kctx->initiator_integ);
508 	kfree(kctx->mech_used.data);
509 	kfree(kctx);
510 }
511 
512 /**
513  * gss_krb5_get_mic - get_mic for the Kerberos GSS mechanism
514  * @gctx: GSS context
515  * @text: plaintext to checksum
516  * @token: buffer into which to write the computed checksum
517  *
518  * Return values:
519  *    %GSS_S_COMPLETE - success, and @token is filled in
520  *    %GSS_S_FAILURE - checksum could not be generated
521  *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
522  */
523 static u32 gss_krb5_get_mic(struct gss_ctx *gctx, struct xdr_buf *text,
524 			    struct xdr_netobj *token)
525 {
526 	struct krb5_ctx *kctx = gctx->internal_ctx_id;
527 
528 	return kctx->gk5e->get_mic(kctx, text, token);
529 }
530 
531 /**
532  * gss_krb5_verify_mic - verify_mic for the Kerberos GSS mechanism
533  * @gctx: GSS context
534  * @message_buffer: plaintext to check
535  * @read_token: received checksum to check
536  *
537  * Return values:
538  *    %GSS_S_COMPLETE - computed and received checksums match
539  *    %GSS_S_DEFECTIVE_TOKEN - received checksum is not valid
540  *    %GSS_S_BAD_SIG - computed and received checksums do not match
541  *    %GSS_S_FAILURE - received checksum could not be checked
542  *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
543  */
544 static u32 gss_krb5_verify_mic(struct gss_ctx *gctx,
545 			       struct xdr_buf *message_buffer,
546 			       struct xdr_netobj *read_token)
547 {
548 	struct krb5_ctx *kctx = gctx->internal_ctx_id;
549 
550 	return kctx->gk5e->verify_mic(kctx, message_buffer, read_token);
551 }
552 
553 /**
554  * gss_krb5_wrap - gss_wrap for the Kerberos GSS mechanism
555  * @gctx: initialized GSS context
556  * @offset: byte offset in @buf to start writing the cipher text
557  * @buf: OUT: send buffer
558  * @pages: plaintext to wrap
559  *
560  * Return values:
561  *    %GSS_S_COMPLETE - success, @buf has been updated
562  *    %GSS_S_FAILURE - @buf could not be wrapped
563  *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
564  */
565 static u32 gss_krb5_wrap(struct gss_ctx *gctx, int offset,
566 			 struct xdr_buf *buf, struct page **pages)
567 {
568 	struct krb5_ctx	*kctx = gctx->internal_ctx_id;
569 
570 	return kctx->gk5e->wrap(kctx, offset, buf, pages);
571 }
572 
573 /**
574  * gss_krb5_unwrap - gss_unwrap for the Kerberos GSS mechanism
575  * @gctx: initialized GSS context
576  * @offset: starting byte offset into @buf
577  * @len: size of ciphertext to unwrap
578  * @buf: ciphertext to unwrap
579  *
580  * Return values:
581  *    %GSS_S_COMPLETE - success, @buf has been updated
582  *    %GSS_S_DEFECTIVE_TOKEN - received blob is not valid
583  *    %GSS_S_BAD_SIG - computed and received checksums do not match
584  *    %GSS_S_FAILURE - @buf could not be unwrapped
585  *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
586  */
587 static u32 gss_krb5_unwrap(struct gss_ctx *gctx, int offset,
588 			   int len, struct xdr_buf *buf)
589 {
590 	struct krb5_ctx	*kctx = gctx->internal_ctx_id;
591 
592 	return kctx->gk5e->unwrap(kctx, offset, len, buf,
593 				  &gctx->slack, &gctx->align);
594 }
595 
596 static const struct gss_api_ops gss_kerberos_ops = {
597 	.gss_import_sec_context	= gss_krb5_import_sec_context,
598 	.gss_get_mic		= gss_krb5_get_mic,
599 	.gss_verify_mic		= gss_krb5_verify_mic,
600 	.gss_wrap		= gss_krb5_wrap,
601 	.gss_unwrap		= gss_krb5_unwrap,
602 	.gss_delete_sec_context	= gss_krb5_delete_sec_context,
603 };
604 
605 static struct pf_desc gss_kerberos_pfs[] = {
606 	[0] = {
607 		.pseudoflavor = RPC_AUTH_GSS_KRB5,
608 		.qop = GSS_C_QOP_DEFAULT,
609 		.service = RPC_GSS_SVC_NONE,
610 		.name = "krb5",
611 	},
612 	[1] = {
613 		.pseudoflavor = RPC_AUTH_GSS_KRB5I,
614 		.qop = GSS_C_QOP_DEFAULT,
615 		.service = RPC_GSS_SVC_INTEGRITY,
616 		.name = "krb5i",
617 		.datatouch = true,
618 	},
619 	[2] = {
620 		.pseudoflavor = RPC_AUTH_GSS_KRB5P,
621 		.qop = GSS_C_QOP_DEFAULT,
622 		.service = RPC_GSS_SVC_PRIVACY,
623 		.name = "krb5p",
624 		.datatouch = true,
625 	},
626 };
627 
628 MODULE_ALIAS("rpc-auth-gss-krb5");
629 MODULE_ALIAS("rpc-auth-gss-krb5i");
630 MODULE_ALIAS("rpc-auth-gss-krb5p");
631 MODULE_ALIAS("rpc-auth-gss-390003");
632 MODULE_ALIAS("rpc-auth-gss-390004");
633 MODULE_ALIAS("rpc-auth-gss-390005");
634 MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2");
635 
636 static struct gss_api_mech gss_kerberos_mech = {
637 	.gm_name	= "krb5",
638 	.gm_owner	= THIS_MODULE,
639 	.gm_oid		= { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" },
640 	.gm_ops		= &gss_kerberos_ops,
641 	.gm_pf_num	= ARRAY_SIZE(gss_kerberos_pfs),
642 	.gm_pfs		= gss_kerberos_pfs,
643 	.gm_upcall_enctypes = gss_krb5_enctype_priority_list,
644 };
645 
646 static int __init init_kerberos_module(void)
647 {
648 	int status;
649 
650 	gss_krb5_prepare_enctype_priority_list();
651 	status = gss_mech_register(&gss_kerberos_mech);
652 	if (status)
653 		printk("Failed to register kerberos gss mechanism!\n");
654 	return status;
655 }
656 
657 static void __exit cleanup_kerberos_module(void)
658 {
659 	gss_mech_unregister(&gss_kerberos_mech);
660 }
661 
662 MODULE_DESCRIPTION("Sun RPC Kerberos 5 module");
663 MODULE_LICENSE("GPL");
664 module_init(init_kerberos_module);
665 module_exit(cleanup_kerberos_module);
666