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 
402 	p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags));
403 	if (IS_ERR(p))
404 		goto out_err;
405 	ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR;
406 
407 	p = simple_get_bytes(p, end, &time32, sizeof(time32));
408 	if (IS_ERR(p))
409 		goto out_err;
410 	/* unsigned 32-bit time overflows in year 2106 */
411 	ctx->endtime = (time64_t)time32;
412 	p = simple_get_bytes(p, end, &seq_send64, sizeof(seq_send64));
413 	if (IS_ERR(p))
414 		goto out_err;
415 	atomic64_set(&ctx->seq_send64, seq_send64);
416 	/* set seq_send for use by "older" enctypes */
417 	atomic_set(&ctx->seq_send, seq_send64);
418 	if (seq_send64 != atomic_read(&ctx->seq_send)) {
419 		dprintk("%s: seq_send64 %llx, seq_send %x overflow?\n", __func__,
420 			seq_send64, atomic_read(&ctx->seq_send));
421 		p = ERR_PTR(-EINVAL);
422 		goto out_err;
423 	}
424 	p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype));
425 	if (IS_ERR(p))
426 		goto out_err;
427 	ctx->gk5e = gss_krb5_lookup_enctype(ctx->enctype);
428 	if (ctx->gk5e == NULL) {
429 		dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n",
430 			ctx->enctype);
431 		p = ERR_PTR(-EINVAL);
432 		goto out_err;
433 	}
434 	keylen = ctx->gk5e->keylength;
435 
436 	p = simple_get_bytes(p, end, ctx->Ksess, keylen);
437 	if (IS_ERR(p))
438 		goto out_err;
439 
440 	if (p != end) {
441 		p = ERR_PTR(-EINVAL);
442 		goto out_err;
443 	}
444 
445 	ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data,
446 				      gss_kerberos_mech.gm_oid.len, gfp_mask);
447 	if (unlikely(ctx->mech_used.data == NULL)) {
448 		p = ERR_PTR(-ENOMEM);
449 		goto out_err;
450 	}
451 	ctx->mech_used.len = gss_kerberos_mech.gm_oid.len;
452 
453 	return gss_krb5_import_ctx_v2(ctx, gfp_mask);
454 
455 out_err:
456 	return PTR_ERR(p);
457 }
458 
459 static int
460 gss_krb5_import_sec_context(const void *p, size_t len, struct gss_ctx *ctx_id,
461 			    time64_t *endtime, gfp_t gfp_mask)
462 {
463 	const void *end = (const void *)((const char *)p + len);
464 	struct  krb5_ctx *ctx;
465 	int ret;
466 
467 	ctx = kzalloc(sizeof(*ctx), gfp_mask);
468 	if (ctx == NULL)
469 		return -ENOMEM;
470 
471 	ret = gss_import_v2_context(p, end, ctx, gfp_mask);
472 	memzero_explicit(&ctx->Ksess, sizeof(ctx->Ksess));
473 	if (ret) {
474 		kfree(ctx);
475 		return ret;
476 	}
477 
478 	ctx_id->internal_ctx_id = ctx;
479 	if (endtime)
480 		*endtime = ctx->endtime;
481 	return 0;
482 }
483 
484 static void
485 gss_krb5_delete_sec_context(void *internal_ctx)
486 {
487 	struct krb5_ctx *kctx = internal_ctx;
488 
489 	crypto_free_sync_skcipher(kctx->seq);
490 	crypto_free_sync_skcipher(kctx->enc);
491 	crypto_free_sync_skcipher(kctx->acceptor_enc);
492 	crypto_free_sync_skcipher(kctx->initiator_enc);
493 	crypto_free_sync_skcipher(kctx->acceptor_enc_aux);
494 	crypto_free_sync_skcipher(kctx->initiator_enc_aux);
495 	crypto_free_ahash(kctx->acceptor_sign);
496 	crypto_free_ahash(kctx->initiator_sign);
497 	crypto_free_ahash(kctx->acceptor_integ);
498 	crypto_free_ahash(kctx->initiator_integ);
499 	kfree(kctx->mech_used.data);
500 	kfree(kctx);
501 }
502 
503 /**
504  * gss_krb5_get_mic - get_mic for the Kerberos GSS mechanism
505  * @gctx: GSS context
506  * @text: plaintext to checksum
507  * @token: buffer into which to write the computed checksum
508  *
509  * Return values:
510  *    %GSS_S_COMPLETE - success, and @token is filled in
511  *    %GSS_S_FAILURE - checksum could not be generated
512  *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
513  */
514 static u32 gss_krb5_get_mic(struct gss_ctx *gctx, struct xdr_buf *text,
515 			    struct xdr_netobj *token)
516 {
517 	struct krb5_ctx *kctx = gctx->internal_ctx_id;
518 
519 	return kctx->gk5e->get_mic(kctx, text, token);
520 }
521 
522 /**
523  * gss_krb5_verify_mic - verify_mic for the Kerberos GSS mechanism
524  * @gctx: GSS context
525  * @message_buffer: plaintext to check
526  * @read_token: received checksum to check
527  *
528  * Return values:
529  *    %GSS_S_COMPLETE - computed and received checksums match
530  *    %GSS_S_DEFECTIVE_TOKEN - received checksum is not valid
531  *    %GSS_S_BAD_SIG - computed and received checksums do not match
532  *    %GSS_S_FAILURE - received checksum could not be checked
533  *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
534  */
535 static u32 gss_krb5_verify_mic(struct gss_ctx *gctx,
536 			       struct xdr_buf *message_buffer,
537 			       struct xdr_netobj *read_token)
538 {
539 	struct krb5_ctx *kctx = gctx->internal_ctx_id;
540 
541 	return kctx->gk5e->verify_mic(kctx, message_buffer, read_token);
542 }
543 
544 /**
545  * gss_krb5_wrap - gss_wrap for the Kerberos GSS mechanism
546  * @gctx: initialized GSS context
547  * @offset: byte offset in @buf to start writing the cipher text
548  * @buf: OUT: send buffer
549  * @pages: plaintext to wrap
550  *
551  * Return values:
552  *    %GSS_S_COMPLETE - success, @buf has been updated
553  *    %GSS_S_FAILURE - @buf could not be wrapped
554  *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
555  */
556 static u32 gss_krb5_wrap(struct gss_ctx *gctx, int offset,
557 			 struct xdr_buf *buf, struct page **pages)
558 {
559 	struct krb5_ctx	*kctx = gctx->internal_ctx_id;
560 
561 	return kctx->gk5e->wrap(kctx, offset, buf, pages);
562 }
563 
564 /**
565  * gss_krb5_unwrap - gss_unwrap for the Kerberos GSS mechanism
566  * @gctx: initialized GSS context
567  * @offset: starting byte offset into @buf
568  * @len: size of ciphertext to unwrap
569  * @buf: ciphertext to unwrap
570  *
571  * Return values:
572  *    %GSS_S_COMPLETE - success, @buf has been updated
573  *    %GSS_S_DEFECTIVE_TOKEN - received blob is not valid
574  *    %GSS_S_BAD_SIG - computed and received checksums do not match
575  *    %GSS_S_FAILURE - @buf could not be unwrapped
576  *    %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid
577  */
578 static u32 gss_krb5_unwrap(struct gss_ctx *gctx, int offset,
579 			   int len, struct xdr_buf *buf)
580 {
581 	struct krb5_ctx	*kctx = gctx->internal_ctx_id;
582 
583 	return kctx->gk5e->unwrap(kctx, offset, len, buf,
584 				  &gctx->slack, &gctx->align);
585 }
586 
587 static const struct gss_api_ops gss_kerberos_ops = {
588 	.gss_import_sec_context	= gss_krb5_import_sec_context,
589 	.gss_get_mic		= gss_krb5_get_mic,
590 	.gss_verify_mic		= gss_krb5_verify_mic,
591 	.gss_wrap		= gss_krb5_wrap,
592 	.gss_unwrap		= gss_krb5_unwrap,
593 	.gss_delete_sec_context	= gss_krb5_delete_sec_context,
594 };
595 
596 static struct pf_desc gss_kerberos_pfs[] = {
597 	[0] = {
598 		.pseudoflavor = RPC_AUTH_GSS_KRB5,
599 		.qop = GSS_C_QOP_DEFAULT,
600 		.service = RPC_GSS_SVC_NONE,
601 		.name = "krb5",
602 	},
603 	[1] = {
604 		.pseudoflavor = RPC_AUTH_GSS_KRB5I,
605 		.qop = GSS_C_QOP_DEFAULT,
606 		.service = RPC_GSS_SVC_INTEGRITY,
607 		.name = "krb5i",
608 		.datatouch = true,
609 	},
610 	[2] = {
611 		.pseudoflavor = RPC_AUTH_GSS_KRB5P,
612 		.qop = GSS_C_QOP_DEFAULT,
613 		.service = RPC_GSS_SVC_PRIVACY,
614 		.name = "krb5p",
615 		.datatouch = true,
616 	},
617 };
618 
619 MODULE_ALIAS("rpc-auth-gss-krb5");
620 MODULE_ALIAS("rpc-auth-gss-krb5i");
621 MODULE_ALIAS("rpc-auth-gss-krb5p");
622 MODULE_ALIAS("rpc-auth-gss-390003");
623 MODULE_ALIAS("rpc-auth-gss-390004");
624 MODULE_ALIAS("rpc-auth-gss-390005");
625 MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2");
626 
627 static struct gss_api_mech gss_kerberos_mech = {
628 	.gm_name	= "krb5",
629 	.gm_owner	= THIS_MODULE,
630 	.gm_oid		= { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" },
631 	.gm_ops		= &gss_kerberos_ops,
632 	.gm_pf_num	= ARRAY_SIZE(gss_kerberos_pfs),
633 	.gm_pfs		= gss_kerberos_pfs,
634 	.gm_upcall_enctypes = gss_krb5_enctype_priority_list,
635 };
636 
637 static int __init init_kerberos_module(void)
638 {
639 	int status;
640 
641 	gss_krb5_prepare_enctype_priority_list();
642 	status = gss_mech_register(&gss_kerberos_mech);
643 	if (status)
644 		printk("Failed to register kerberos gss mechanism!\n");
645 	return status;
646 }
647 
648 static void __exit cleanup_kerberos_module(void)
649 {
650 	gss_mech_unregister(&gss_kerberos_mech);
651 }
652 
653 MODULE_LICENSE("GPL");
654 module_init(init_kerberos_module);
655 module_exit(cleanup_kerberos_module);
656