Commit | Line | Data |
---|---|---|
2573a464 | 1 | // SPDX-License-Identifier: BSD-3-Clause |
1da177e4 LT |
2 | /* |
3 | * linux/net/sunrpc/gss_krb5_mech.c | |
4 | * | |
81d4a433 | 5 | * Copyright (c) 2001-2008 The Regents of the University of Michigan. |
1da177e4 LT |
6 | * All rights reserved. |
7 | * | |
8 | * Andy Adamson <andros@umich.edu> | |
9 | * J. Bruce Fields <bfields@umich.edu> | |
1da177e4 LT |
10 | */ |
11 | ||
3b5cf20c HX |
12 | #include <crypto/hash.h> |
13 | #include <crypto/skcipher.h> | |
378c6697 | 14 | #include <linux/err.h> |
1da177e4 LT |
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> | |
1da177e4 LT |
20 | #include <linux/sunrpc/gss_krb5.h> |
21 | #include <linux/sunrpc/xdr.h> | |
b084f598 | 22 | #include <linux/sunrpc/gss_krb5_enctypes.h> |
1da177e4 | 23 | |
f895b252 | 24 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
1da177e4 LT |
25 | # define RPCDBG_FACILITY RPCDBG_AUTH |
26 | #endif | |
27 | ||
47d84807 KC |
28 | static struct gss_api_mech gss_kerberos_mech; /* forward declaration */ |
29 | ||
81d4a433 | 30 | static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { |
fe9a2705 | 31 | #ifndef CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES |
81d4a433 KC |
32 | /* |
33 | * DES (All DES enctypes are mapped to the same gss functionality) | |
34 | */ | |
35 | { | |
36 | .etype = ENCTYPE_DES_CBC_RAW, | |
37 | .ctype = CKSUMTYPE_RSA_MD5, | |
38 | .name = "des-cbc-crc", | |
39 | .encrypt_name = "cbc(des)", | |
40 | .cksum_name = "md5", | |
41 | .encrypt = krb5_encrypt, | |
42 | .decrypt = krb5_decrypt, | |
4891f2d0 | 43 | .mk_key = NULL, |
81d4a433 KC |
44 | .signalg = SGN_ALG_DES_MAC_MD5, |
45 | .sealalg = SEAL_ALG_DES, | |
46 | .keybytes = 7, | |
47 | .keylength = 8, | |
48 | .blocksize = 8, | |
5af46547 | 49 | .conflen = 8, |
81d4a433 | 50 | .cksumlength = 8, |
e1f6c07b | 51 | .keyed_cksum = 0, |
81d4a433 | 52 | }, |
fe9a2705 | 53 | #endif /* CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES */ |
fffdaef2 KC |
54 | /* |
55 | * RC4-HMAC | |
56 | */ | |
57 | { | |
58 | .etype = ENCTYPE_ARCFOUR_HMAC, | |
59 | .ctype = CKSUMTYPE_HMAC_MD5_ARCFOUR, | |
60 | .name = "rc4-hmac", | |
61 | .encrypt_name = "ecb(arc4)", | |
62 | .cksum_name = "hmac(md5)", | |
63 | .encrypt = krb5_encrypt, | |
64 | .decrypt = krb5_decrypt, | |
65 | .mk_key = NULL, | |
66 | .signalg = SGN_ALG_HMAC_MD5, | |
67 | .sealalg = SEAL_ALG_MICROSOFT_RC4, | |
68 | .keybytes = 16, | |
69 | .keylength = 16, | |
70 | .blocksize = 1, | |
71 | .conflen = 8, | |
72 | .cksumlength = 8, | |
73 | .keyed_cksum = 1, | |
74 | }, | |
958142e9 KC |
75 | /* |
76 | * 3DES | |
77 | */ | |
78 | { | |
79 | .etype = ENCTYPE_DES3_CBC_RAW, | |
80 | .ctype = CKSUMTYPE_HMAC_SHA1_DES3, | |
81 | .name = "des3-hmac-sha1", | |
82 | .encrypt_name = "cbc(des3_ede)", | |
83 | .cksum_name = "hmac(sha1)", | |
84 | .encrypt = krb5_encrypt, | |
85 | .decrypt = krb5_decrypt, | |
86 | .mk_key = gss_krb5_des3_make_key, | |
87 | .signalg = SGN_ALG_HMAC_SHA1_DES3_KD, | |
88 | .sealalg = SEAL_ALG_DES3KD, | |
89 | .keybytes = 21, | |
90 | .keylength = 24, | |
91 | .blocksize = 8, | |
5af46547 | 92 | .conflen = 8, |
958142e9 KC |
93 | .cksumlength = 20, |
94 | .keyed_cksum = 1, | |
95 | }, | |
934a95aa KC |
96 | /* |
97 | * AES128 | |
98 | */ | |
99 | { | |
100 | .etype = ENCTYPE_AES128_CTS_HMAC_SHA1_96, | |
101 | .ctype = CKSUMTYPE_HMAC_SHA1_96_AES128, | |
102 | .name = "aes128-cts", | |
103 | .encrypt_name = "cts(cbc(aes))", | |
104 | .cksum_name = "hmac(sha1)", | |
105 | .encrypt = krb5_encrypt, | |
106 | .decrypt = krb5_decrypt, | |
107 | .mk_key = gss_krb5_aes_make_key, | |
108 | .encrypt_v2 = gss_krb5_aes_encrypt, | |
109 | .decrypt_v2 = gss_krb5_aes_decrypt, | |
110 | .signalg = -1, | |
111 | .sealalg = -1, | |
112 | .keybytes = 16, | |
113 | .keylength = 16, | |
114 | .blocksize = 16, | |
5af46547 | 115 | .conflen = 16, |
934a95aa KC |
116 | .cksumlength = 12, |
117 | .keyed_cksum = 1, | |
118 | }, | |
119 | /* | |
120 | * AES256 | |
121 | */ | |
122 | { | |
123 | .etype = ENCTYPE_AES256_CTS_HMAC_SHA1_96, | |
124 | .ctype = CKSUMTYPE_HMAC_SHA1_96_AES256, | |
125 | .name = "aes256-cts", | |
126 | .encrypt_name = "cts(cbc(aes))", | |
127 | .cksum_name = "hmac(sha1)", | |
128 | .encrypt = krb5_encrypt, | |
129 | .decrypt = krb5_decrypt, | |
130 | .mk_key = gss_krb5_aes_make_key, | |
131 | .encrypt_v2 = gss_krb5_aes_encrypt, | |
132 | .decrypt_v2 = gss_krb5_aes_decrypt, | |
133 | .signalg = -1, | |
134 | .sealalg = -1, | |
135 | .keybytes = 32, | |
136 | .keylength = 32, | |
137 | .blocksize = 16, | |
5af46547 | 138 | .conflen = 16, |
934a95aa KC |
139 | .cksumlength = 12, |
140 | .keyed_cksum = 1, | |
141 | }, | |
81d4a433 KC |
142 | }; |
143 | ||
144 | static const int num_supported_enctypes = | |
145 | ARRAY_SIZE(supported_gss_krb5_enctypes); | |
146 | ||
147 | static int | |
148 | supported_gss_krb5_enctype(int etype) | |
149 | { | |
150 | int i; | |
151 | for (i = 0; i < num_supported_enctypes; i++) | |
152 | if (supported_gss_krb5_enctypes[i].etype == etype) | |
153 | return 1; | |
154 | return 0; | |
155 | } | |
156 | ||
157 | static const struct gss_krb5_enctype * | |
158 | get_gss_krb5_enctype(int etype) | |
159 | { | |
160 | int i; | |
161 | for (i = 0; i < num_supported_enctypes; i++) | |
162 | if (supported_gss_krb5_enctypes[i].etype == etype) | |
163 | return &supported_gss_krb5_enctypes[i]; | |
164 | return NULL; | |
165 | } | |
166 | ||
1da177e4 LT |
167 | static const void * |
168 | simple_get_bytes(const void *p, const void *end, void *res, int len) | |
169 | { | |
170 | const void *q = (const void *)((const char *)p + len); | |
171 | if (unlikely(q > end || q < p)) | |
172 | return ERR_PTR(-EFAULT); | |
173 | memcpy(res, p, len); | |
174 | return q; | |
175 | } | |
176 | ||
177 | static const void * | |
178 | simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) | |
179 | { | |
180 | const void *q; | |
181 | unsigned int len; | |
182 | ||
183 | p = simple_get_bytes(p, end, &len, sizeof(len)); | |
184 | if (IS_ERR(p)) | |
185 | return p; | |
186 | q = (const void *)((const char *)p + len); | |
187 | if (unlikely(q > end || q < p)) | |
188 | return ERR_PTR(-EFAULT); | |
0f38b873 | 189 | res->data = kmemdup(p, len, GFP_NOFS); |
1da177e4 LT |
190 | if (unlikely(res->data == NULL)) |
191 | return ERR_PTR(-ENOMEM); | |
1da177e4 LT |
192 | res->len = len; |
193 | return q; | |
194 | } | |
195 | ||
196 | static inline const void * | |
81d4a433 | 197 | get_key(const void *p, const void *end, |
e9e575b8 | 198 | struct krb5_ctx *ctx, struct crypto_sync_skcipher **res) |
1da177e4 LT |
199 | { |
200 | struct xdr_netobj key; | |
378c6697 | 201 | int alg; |
1da177e4 LT |
202 | |
203 | p = simple_get_bytes(p, end, &alg, sizeof(alg)); | |
204 | if (IS_ERR(p)) | |
205 | goto out_err; | |
81d4a433 KC |
206 | |
207 | switch (alg) { | |
208 | case ENCTYPE_DES_CBC_CRC: | |
209 | case ENCTYPE_DES_CBC_MD4: | |
210 | case ENCTYPE_DES_CBC_MD5: | |
211 | /* Map all these key types to ENCTYPE_DES_CBC_RAW */ | |
212 | alg = ENCTYPE_DES_CBC_RAW; | |
213 | break; | |
214 | } | |
215 | ||
216 | if (!supported_gss_krb5_enctype(alg)) { | |
217 | printk(KERN_WARNING "gss_kerberos_mech: unsupported " | |
218 | "encryption key algorithm %d\n", alg); | |
ce8477e1 | 219 | p = ERR_PTR(-EINVAL); |
81d4a433 KC |
220 | goto out_err; |
221 | } | |
1da177e4 LT |
222 | p = simple_get_netobj(p, end, &key); |
223 | if (IS_ERR(p)) | |
224 | goto out_err; | |
225 | ||
e9e575b8 | 226 | *res = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0); |
378c6697 | 227 | if (IS_ERR(*res)) { |
81d4a433 KC |
228 | printk(KERN_WARNING "gss_kerberos_mech: unable to initialize " |
229 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | |
378c6697 | 230 | *res = NULL; |
1da177e4 | 231 | goto out_err_free_key; |
9e56904e | 232 | } |
e9e575b8 | 233 | if (crypto_sync_skcipher_setkey(*res, key.data, key.len)) { |
81d4a433 KC |
234 | printk(KERN_WARNING "gss_kerberos_mech: error setting key for " |
235 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | |
1da177e4 | 236 | goto out_err_free_tfm; |
9e56904e | 237 | } |
1da177e4 LT |
238 | |
239 | kfree(key.data); | |
240 | return p; | |
241 | ||
242 | out_err_free_tfm: | |
e9e575b8 | 243 | crypto_free_sync_skcipher(*res); |
1da177e4 LT |
244 | out_err_free_key: |
245 | kfree(key.data); | |
246 | p = ERR_PTR(-EINVAL); | |
247 | out_err: | |
248 | return p; | |
249 | } | |
250 | ||
251 | static int | |
a8cc1cb7 | 252 | gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx) |
1da177e4 | 253 | { |
c3be6577 | 254 | u32 seq_send; |
e678e06b | 255 | int tmp; |
1da177e4 | 256 | |
1da177e4 LT |
257 | p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); |
258 | if (IS_ERR(p)) | |
a8cc1cb7 KC |
259 | goto out_err; |
260 | ||
261 | /* Old format supports only DES! Any other enctype uses new format */ | |
1ac3719a | 262 | ctx->enctype = ENCTYPE_DES_CBC_RAW; |
a8cc1cb7 | 263 | |
81d4a433 | 264 | ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); |
ce8477e1 BN |
265 | if (ctx->gk5e == NULL) { |
266 | p = ERR_PTR(-EINVAL); | |
81d4a433 | 267 | goto out_err; |
ce8477e1 | 268 | } |
81d4a433 | 269 | |
717757ad BF |
270 | /* The downcall format was designed before we completely understood |
271 | * the uses of the context fields; so it includes some stuff we | |
272 | * just give some minimal sanity-checking, and some we ignore | |
273 | * completely (like the next twenty bytes): */ | |
ce8477e1 BN |
274 | if (unlikely(p + 20 > end || p + 20 < p)) { |
275 | p = ERR_PTR(-EFAULT); | |
a8cc1cb7 | 276 | goto out_err; |
ce8477e1 | 277 | } |
717757ad | 278 | p += 20; |
e678e06b | 279 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); |
1da177e4 | 280 | if (IS_ERR(p)) |
a8cc1cb7 | 281 | goto out_err; |
ef338bee KC |
282 | if (tmp != SGN_ALG_DES_MAC_MD5) { |
283 | p = ERR_PTR(-ENOSYS); | |
a8cc1cb7 | 284 | goto out_err; |
ef338bee | 285 | } |
d922a84a | 286 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); |
1da177e4 | 287 | if (IS_ERR(p)) |
a8cc1cb7 | 288 | goto out_err; |
ef338bee KC |
289 | if (tmp != SEAL_ALG_DES) { |
290 | p = ERR_PTR(-ENOSYS); | |
a8cc1cb7 | 291 | goto out_err; |
ef338bee | 292 | } |
1da177e4 LT |
293 | p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); |
294 | if (IS_ERR(p)) | |
a8cc1cb7 | 295 | goto out_err; |
c3be6577 | 296 | p = simple_get_bytes(p, end, &seq_send, sizeof(seq_send)); |
1da177e4 | 297 | if (IS_ERR(p)) |
a8cc1cb7 | 298 | goto out_err; |
c3be6577 | 299 | atomic_set(&ctx->seq_send, seq_send); |
1da177e4 LT |
300 | p = simple_get_netobj(p, end, &ctx->mech_used); |
301 | if (IS_ERR(p)) | |
a8cc1cb7 | 302 | goto out_err; |
81d4a433 | 303 | p = get_key(p, end, ctx, &ctx->enc); |
1da177e4 LT |
304 | if (IS_ERR(p)) |
305 | goto out_err_free_mech; | |
81d4a433 | 306 | p = get_key(p, end, ctx, &ctx->seq); |
1da177e4 LT |
307 | if (IS_ERR(p)) |
308 | goto out_err_free_key1; | |
309 | if (p != end) { | |
310 | p = ERR_PTR(-EFAULT); | |
311 | goto out_err_free_key2; | |
312 | } | |
313 | ||
1da177e4 LT |
314 | return 0; |
315 | ||
316 | out_err_free_key2: | |
e9e575b8 | 317 | crypto_free_sync_skcipher(ctx->seq); |
1da177e4 | 318 | out_err_free_key1: |
e9e575b8 | 319 | crypto_free_sync_skcipher(ctx->enc); |
1da177e4 LT |
320 | out_err_free_mech: |
321 | kfree(ctx->mech_used.data); | |
1da177e4 LT |
322 | out_err: |
323 | return PTR_ERR(p); | |
324 | } | |
325 | ||
e9e575b8 | 326 | static struct crypto_sync_skcipher * |
934a95aa | 327 | context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key) |
47d84807 | 328 | { |
e9e575b8 | 329 | struct crypto_sync_skcipher *cp; |
47d84807 | 330 | |
e9e575b8 | 331 | cp = crypto_alloc_sync_skcipher(cname, 0, 0); |
47d84807 KC |
332 | if (IS_ERR(cp)) { |
333 | dprintk("gss_kerberos_mech: unable to initialize " | |
934a95aa | 334 | "crypto algorithm %s\n", cname); |
47d84807 KC |
335 | return NULL; |
336 | } | |
e9e575b8 | 337 | if (crypto_sync_skcipher_setkey(cp, key, ctx->gk5e->keylength)) { |
47d84807 | 338 | dprintk("gss_kerberos_mech: error setting key for " |
934a95aa | 339 | "crypto algorithm %s\n", cname); |
e9e575b8 | 340 | crypto_free_sync_skcipher(cp); |
47d84807 KC |
341 | return NULL; |
342 | } | |
343 | return cp; | |
344 | } | |
345 | ||
346 | static inline void | |
347 | set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed) | |
348 | { | |
349 | cdata[0] = (usage>>24)&0xff; | |
350 | cdata[1] = (usage>>16)&0xff; | |
351 | cdata[2] = (usage>>8)&0xff; | |
352 | cdata[3] = usage&0xff; | |
353 | cdata[4] = seed; | |
354 | } | |
355 | ||
356 | static int | |
1f4c86c0 | 357 | context_derive_keys_des3(struct krb5_ctx *ctx, gfp_t gfp_mask) |
47d84807 KC |
358 | { |
359 | struct xdr_netobj c, keyin, keyout; | |
360 | u8 cdata[GSS_KRB5_K5CLENGTH]; | |
361 | u32 err; | |
362 | ||
363 | c.len = GSS_KRB5_K5CLENGTH; | |
364 | c.data = cdata; | |
365 | ||
fc263a91 KC |
366 | keyin.data = ctx->Ksess; |
367 | keyin.len = ctx->gk5e->keylength; | |
368 | keyout.len = ctx->gk5e->keylength; | |
47d84807 KC |
369 | |
370 | /* seq uses the raw key */ | |
934a95aa | 371 | ctx->seq = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, |
fc263a91 | 372 | ctx->Ksess); |
47d84807 KC |
373 | if (ctx->seq == NULL) |
374 | goto out_err; | |
375 | ||
934a95aa | 376 | ctx->enc = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, |
fc263a91 | 377 | ctx->Ksess); |
47d84807 KC |
378 | if (ctx->enc == NULL) |
379 | goto out_free_seq; | |
380 | ||
381 | /* derive cksum */ | |
382 | set_cdata(cdata, KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM); | |
383 | keyout.data = ctx->cksum; | |
1f4c86c0 | 384 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
385 | if (err) { |
386 | dprintk("%s: Error %d deriving cksum key\n", | |
387 | __func__, err); | |
388 | goto out_free_enc; | |
389 | } | |
390 | ||
391 | return 0; | |
392 | ||
393 | out_free_enc: | |
e9e575b8 | 394 | crypto_free_sync_skcipher(ctx->enc); |
47d84807 | 395 | out_free_seq: |
e9e575b8 | 396 | crypto_free_sync_skcipher(ctx->seq); |
47d84807 KC |
397 | out_err: |
398 | return -EINVAL; | |
399 | } | |
400 | ||
fffdaef2 KC |
401 | /* |
402 | * Note that RC4 depends on deriving keys using the sequence | |
403 | * number or the checksum of a token. Therefore, the final keys | |
404 | * cannot be calculated until the token is being constructed! | |
405 | */ | |
406 | static int | |
407 | context_derive_keys_rc4(struct krb5_ctx *ctx) | |
408 | { | |
3b5cf20c | 409 | struct crypto_shash *hmac; |
0867659f | 410 | char sigkeyconstant[] = "signaturekey"; |
fffdaef2 | 411 | int slen = strlen(sigkeyconstant) + 1; /* include null terminator */ |
3b5cf20c | 412 | struct shash_desc *desc; |
fffdaef2 KC |
413 | int err; |
414 | ||
415 | dprintk("RPC: %s: entered\n", __func__); | |
416 | /* | |
417 | * derive cksum (aka Ksign) key | |
418 | */ | |
3b5cf20c | 419 | hmac = crypto_alloc_shash(ctx->gk5e->cksum_name, 0, 0); |
fffdaef2 KC |
420 | if (IS_ERR(hmac)) { |
421 | dprintk("%s: error %ld allocating hash '%s'\n", | |
422 | __func__, PTR_ERR(hmac), ctx->gk5e->cksum_name); | |
423 | err = PTR_ERR(hmac); | |
424 | goto out_err; | |
425 | } | |
426 | ||
3b5cf20c | 427 | err = crypto_shash_setkey(hmac, ctx->Ksess, ctx->gk5e->keylength); |
fffdaef2 KC |
428 | if (err) |
429 | goto out_err_free_hmac; | |
430 | ||
fffdaef2 | 431 | |
56094edd | 432 | desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac), GFP_NOFS); |
3b5cf20c HX |
433 | if (!desc) { |
434 | dprintk("%s: failed to allocate hash descriptor for '%s'\n", | |
435 | __func__, ctx->gk5e->cksum_name); | |
436 | err = -ENOMEM; | |
fffdaef2 | 437 | goto out_err_free_hmac; |
3b5cf20c HX |
438 | } |
439 | ||
440 | desc->tfm = hmac; | |
fffdaef2 | 441 | |
3b5cf20c HX |
442 | err = crypto_shash_digest(desc, sigkeyconstant, slen, ctx->cksum); |
443 | kzfree(desc); | |
fffdaef2 KC |
444 | if (err) |
445 | goto out_err_free_hmac; | |
446 | /* | |
3b5cf20c | 447 | * allocate hash, and skciphers for data and seqnum encryption |
fffdaef2 | 448 | */ |
e9e575b8 | 449 | ctx->enc = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0); |
fffdaef2 KC |
450 | if (IS_ERR(ctx->enc)) { |
451 | err = PTR_ERR(ctx->enc); | |
452 | goto out_err_free_hmac; | |
453 | } | |
454 | ||
e9e575b8 | 455 | ctx->seq = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0); |
fffdaef2 | 456 | if (IS_ERR(ctx->seq)) { |
e9e575b8 | 457 | crypto_free_sync_skcipher(ctx->enc); |
fffdaef2 KC |
458 | err = PTR_ERR(ctx->seq); |
459 | goto out_err_free_hmac; | |
460 | } | |
461 | ||
462 | dprintk("RPC: %s: returning success\n", __func__); | |
463 | ||
464 | err = 0; | |
465 | ||
466 | out_err_free_hmac: | |
3b5cf20c | 467 | crypto_free_shash(hmac); |
fffdaef2 KC |
468 | out_err: |
469 | dprintk("RPC: %s: returning %d\n", __func__, err); | |
470 | return err; | |
471 | } | |
472 | ||
47d84807 | 473 | static int |
1f4c86c0 | 474 | context_derive_keys_new(struct krb5_ctx *ctx, gfp_t gfp_mask) |
47d84807 KC |
475 | { |
476 | struct xdr_netobj c, keyin, keyout; | |
477 | u8 cdata[GSS_KRB5_K5CLENGTH]; | |
478 | u32 err; | |
479 | ||
480 | c.len = GSS_KRB5_K5CLENGTH; | |
481 | c.data = cdata; | |
482 | ||
fc263a91 KC |
483 | keyin.data = ctx->Ksess; |
484 | keyin.len = ctx->gk5e->keylength; | |
485 | keyout.len = ctx->gk5e->keylength; | |
47d84807 KC |
486 | |
487 | /* initiator seal encryption */ | |
488 | set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); | |
489 | keyout.data = ctx->initiator_seal; | |
1f4c86c0 | 490 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
491 | if (err) { |
492 | dprintk("%s: Error %d deriving initiator_seal key\n", | |
493 | __func__, err); | |
494 | goto out_err; | |
495 | } | |
934a95aa KC |
496 | ctx->initiator_enc = context_v2_alloc_cipher(ctx, |
497 | ctx->gk5e->encrypt_name, | |
498 | ctx->initiator_seal); | |
47d84807 KC |
499 | if (ctx->initiator_enc == NULL) |
500 | goto out_err; | |
501 | ||
502 | /* acceptor seal encryption */ | |
503 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); | |
504 | keyout.data = ctx->acceptor_seal; | |
1f4c86c0 | 505 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
506 | if (err) { |
507 | dprintk("%s: Error %d deriving acceptor_seal key\n", | |
508 | __func__, err); | |
509 | goto out_free_initiator_enc; | |
510 | } | |
934a95aa KC |
511 | ctx->acceptor_enc = context_v2_alloc_cipher(ctx, |
512 | ctx->gk5e->encrypt_name, | |
513 | ctx->acceptor_seal); | |
47d84807 KC |
514 | if (ctx->acceptor_enc == NULL) |
515 | goto out_free_initiator_enc; | |
516 | ||
517 | /* initiator sign checksum */ | |
518 | set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM); | |
519 | keyout.data = ctx->initiator_sign; | |
1f4c86c0 | 520 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
521 | if (err) { |
522 | dprintk("%s: Error %d deriving initiator_sign key\n", | |
523 | __func__, err); | |
524 | goto out_free_acceptor_enc; | |
525 | } | |
526 | ||
527 | /* acceptor sign checksum */ | |
528 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM); | |
529 | keyout.data = ctx->acceptor_sign; | |
1f4c86c0 | 530 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
531 | if (err) { |
532 | dprintk("%s: Error %d deriving acceptor_sign key\n", | |
533 | __func__, err); | |
534 | goto out_free_acceptor_enc; | |
535 | } | |
536 | ||
537 | /* initiator seal integrity */ | |
538 | set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY); | |
539 | keyout.data = ctx->initiator_integ; | |
1f4c86c0 | 540 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
541 | if (err) { |
542 | dprintk("%s: Error %d deriving initiator_integ key\n", | |
543 | __func__, err); | |
544 | goto out_free_acceptor_enc; | |
545 | } | |
546 | ||
547 | /* acceptor seal integrity */ | |
548 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_INTEGRITY); | |
549 | keyout.data = ctx->acceptor_integ; | |
1f4c86c0 | 550 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
551 | if (err) { |
552 | dprintk("%s: Error %d deriving acceptor_integ key\n", | |
553 | __func__, err); | |
554 | goto out_free_acceptor_enc; | |
555 | } | |
556 | ||
934a95aa KC |
557 | switch (ctx->enctype) { |
558 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | |
559 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | |
560 | ctx->initiator_enc_aux = | |
561 | context_v2_alloc_cipher(ctx, "cbc(aes)", | |
562 | ctx->initiator_seal); | |
563 | if (ctx->initiator_enc_aux == NULL) | |
564 | goto out_free_acceptor_enc; | |
565 | ctx->acceptor_enc_aux = | |
566 | context_v2_alloc_cipher(ctx, "cbc(aes)", | |
567 | ctx->acceptor_seal); | |
568 | if (ctx->acceptor_enc_aux == NULL) { | |
e9e575b8 | 569 | crypto_free_sync_skcipher(ctx->initiator_enc_aux); |
934a95aa KC |
570 | goto out_free_acceptor_enc; |
571 | } | |
572 | } | |
573 | ||
47d84807 KC |
574 | return 0; |
575 | ||
576 | out_free_acceptor_enc: | |
e9e575b8 | 577 | crypto_free_sync_skcipher(ctx->acceptor_enc); |
47d84807 | 578 | out_free_initiator_enc: |
e9e575b8 | 579 | crypto_free_sync_skcipher(ctx->initiator_enc); |
47d84807 KC |
580 | out_err: |
581 | return -EINVAL; | |
582 | } | |
583 | ||
584 | static int | |
1f4c86c0 TM |
585 | gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx, |
586 | gfp_t gfp_mask) | |
47d84807 | 587 | { |
c3be6577 | 588 | u64 seq_send64; |
47d84807 KC |
589 | int keylen; |
590 | ||
591 | p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags)); | |
592 | if (IS_ERR(p)) | |
593 | goto out_err; | |
594 | ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR; | |
595 | ||
596 | p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); | |
597 | if (IS_ERR(p)) | |
598 | goto out_err; | |
c3be6577 | 599 | p = simple_get_bytes(p, end, &seq_send64, sizeof(seq_send64)); |
47d84807 KC |
600 | if (IS_ERR(p)) |
601 | goto out_err; | |
c3be6577 | 602 | atomic64_set(&ctx->seq_send64, seq_send64); |
47d84807 | 603 | /* set seq_send for use by "older" enctypes */ |
c3be6577 PB |
604 | atomic_set(&ctx->seq_send, seq_send64); |
605 | if (seq_send64 != atomic_read(&ctx->seq_send)) { | |
606 | dprintk("%s: seq_send64 %llx, seq_send %x overflow?\n", __func__, | |
607 | seq_send64, atomic_read(&ctx->seq_send)); | |
ce8477e1 | 608 | p = ERR_PTR(-EINVAL); |
47d84807 KC |
609 | goto out_err; |
610 | } | |
611 | p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype)); | |
612 | if (IS_ERR(p)) | |
613 | goto out_err; | |
958142e9 KC |
614 | /* Map ENCTYPE_DES3_CBC_SHA1 to ENCTYPE_DES3_CBC_RAW */ |
615 | if (ctx->enctype == ENCTYPE_DES3_CBC_SHA1) | |
616 | ctx->enctype = ENCTYPE_DES3_CBC_RAW; | |
47d84807 KC |
617 | ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); |
618 | if (ctx->gk5e == NULL) { | |
619 | dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n", | |
620 | ctx->enctype); | |
621 | p = ERR_PTR(-EINVAL); | |
622 | goto out_err; | |
623 | } | |
624 | keylen = ctx->gk5e->keylength; | |
625 | ||
fc263a91 | 626 | p = simple_get_bytes(p, end, ctx->Ksess, keylen); |
47d84807 KC |
627 | if (IS_ERR(p)) |
628 | goto out_err; | |
629 | ||
630 | if (p != end) { | |
631 | p = ERR_PTR(-EINVAL); | |
632 | goto out_err; | |
633 | } | |
634 | ||
635 | ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data, | |
1f4c86c0 | 636 | gss_kerberos_mech.gm_oid.len, gfp_mask); |
47d84807 KC |
637 | if (unlikely(ctx->mech_used.data == NULL)) { |
638 | p = ERR_PTR(-ENOMEM); | |
639 | goto out_err; | |
640 | } | |
641 | ctx->mech_used.len = gss_kerberos_mech.gm_oid.len; | |
642 | ||
643 | switch (ctx->enctype) { | |
644 | case ENCTYPE_DES3_CBC_RAW: | |
1f4c86c0 | 645 | return context_derive_keys_des3(ctx, gfp_mask); |
fffdaef2 KC |
646 | case ENCTYPE_ARCFOUR_HMAC: |
647 | return context_derive_keys_rc4(ctx); | |
47d84807 KC |
648 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: |
649 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | |
1f4c86c0 | 650 | return context_derive_keys_new(ctx, gfp_mask); |
47d84807 KC |
651 | default: |
652 | return -EINVAL; | |
653 | } | |
654 | ||
655 | out_err: | |
656 | return PTR_ERR(p); | |
657 | } | |
658 | ||
a8cc1cb7 KC |
659 | static int |
660 | gss_import_sec_context_kerberos(const void *p, size_t len, | |
1f4c86c0 | 661 | struct gss_ctx *ctx_id, |
400f26b5 | 662 | time_t *endtime, |
1f4c86c0 | 663 | gfp_t gfp_mask) |
a8cc1cb7 KC |
664 | { |
665 | const void *end = (const void *)((const char *)p + len); | |
666 | struct krb5_ctx *ctx; | |
667 | int ret; | |
668 | ||
1f4c86c0 | 669 | ctx = kzalloc(sizeof(*ctx), gfp_mask); |
a8cc1cb7 KC |
670 | if (ctx == NULL) |
671 | return -ENOMEM; | |
672 | ||
673 | if (len == 85) | |
674 | ret = gss_import_v1_context(p, end, ctx); | |
675 | else | |
1f4c86c0 | 676 | ret = gss_import_v2_context(p, end, ctx, gfp_mask); |
a8cc1cb7 | 677 | |
400f26b5 | 678 | if (ret == 0) { |
a8cc1cb7 | 679 | ctx_id->internal_ctx_id = ctx; |
400f26b5 SS |
680 | if (endtime) |
681 | *endtime = ctx->endtime; | |
682 | } else | |
a8cc1cb7 KC |
683 | kfree(ctx); |
684 | ||
685 | dprintk("RPC: %s: returning %d\n", __func__, ret); | |
686 | return ret; | |
687 | } | |
688 | ||
1da177e4 LT |
689 | static void |
690 | gss_delete_sec_context_kerberos(void *internal_ctx) { | |
691 | struct krb5_ctx *kctx = internal_ctx; | |
692 | ||
e9e575b8 KC |
693 | crypto_free_sync_skcipher(kctx->seq); |
694 | crypto_free_sync_skcipher(kctx->enc); | |
695 | crypto_free_sync_skcipher(kctx->acceptor_enc); | |
696 | crypto_free_sync_skcipher(kctx->initiator_enc); | |
697 | crypto_free_sync_skcipher(kctx->acceptor_enc_aux); | |
698 | crypto_free_sync_skcipher(kctx->initiator_enc_aux); | |
573dbd95 | 699 | kfree(kctx->mech_used.data); |
1da177e4 LT |
700 | kfree(kctx); |
701 | } | |
702 | ||
f1c0a861 | 703 | static const struct gss_api_ops gss_kerberos_ops = { |
1da177e4 LT |
704 | .gss_import_sec_context = gss_import_sec_context_kerberos, |
705 | .gss_get_mic = gss_get_mic_kerberos, | |
706 | .gss_verify_mic = gss_verify_mic_kerberos, | |
14ae162c BF |
707 | .gss_wrap = gss_wrap_kerberos, |
708 | .gss_unwrap = gss_unwrap_kerberos, | |
1da177e4 LT |
709 | .gss_delete_sec_context = gss_delete_sec_context_kerberos, |
710 | }; | |
711 | ||
712 | static struct pf_desc gss_kerberos_pfs[] = { | |
713 | [0] = { | |
714 | .pseudoflavor = RPC_AUTH_GSS_KRB5, | |
83523d08 | 715 | .qop = GSS_C_QOP_DEFAULT, |
1da177e4 LT |
716 | .service = RPC_GSS_SVC_NONE, |
717 | .name = "krb5", | |
718 | }, | |
719 | [1] = { | |
720 | .pseudoflavor = RPC_AUTH_GSS_KRB5I, | |
83523d08 | 721 | .qop = GSS_C_QOP_DEFAULT, |
1da177e4 LT |
722 | .service = RPC_GSS_SVC_INTEGRITY, |
723 | .name = "krb5i", | |
65b80179 | 724 | .datatouch = true, |
1da177e4 | 725 | }, |
14ae162c BF |
726 | [2] = { |
727 | .pseudoflavor = RPC_AUTH_GSS_KRB5P, | |
83523d08 | 728 | .qop = GSS_C_QOP_DEFAULT, |
14ae162c BF |
729 | .service = RPC_GSS_SVC_PRIVACY, |
730 | .name = "krb5p", | |
65b80179 | 731 | .datatouch = true, |
14ae162c | 732 | }, |
1da177e4 LT |
733 | }; |
734 | ||
058c5c99 BF |
735 | MODULE_ALIAS("rpc-auth-gss-krb5"); |
736 | MODULE_ALIAS("rpc-auth-gss-krb5i"); | |
737 | MODULE_ALIAS("rpc-auth-gss-krb5p"); | |
738 | MODULE_ALIAS("rpc-auth-gss-390003"); | |
739 | MODULE_ALIAS("rpc-auth-gss-390004"); | |
740 | MODULE_ALIAS("rpc-auth-gss-390005"); | |
f783288f | 741 | MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2"); |
058c5c99 | 742 | |
1da177e4 LT |
743 | static struct gss_api_mech gss_kerberos_mech = { |
744 | .gm_name = "krb5", | |
745 | .gm_owner = THIS_MODULE, | |
fb15b26f | 746 | .gm_oid = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }, |
1da177e4 LT |
747 | .gm_ops = &gss_kerberos_ops, |
748 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), | |
749 | .gm_pfs = gss_kerberos_pfs, | |
b084f598 | 750 | .gm_upcall_enctypes = KRB5_SUPPORTED_ENCTYPES, |
1da177e4 LT |
751 | }; |
752 | ||
753 | static int __init init_kerberos_module(void) | |
754 | { | |
755 | int status; | |
756 | ||
757 | status = gss_mech_register(&gss_kerberos_mech); | |
758 | if (status) | |
759 | printk("Failed to register kerberos gss mechanism!\n"); | |
760 | return status; | |
761 | } | |
762 | ||
763 | static void __exit cleanup_kerberos_module(void) | |
764 | { | |
765 | gss_mech_unregister(&gss_kerberos_mech); | |
766 | } | |
767 | ||
768 | MODULE_LICENSE("GPL"); | |
769 | module_init(init_kerberos_module); | |
770 | module_exit(cleanup_kerberos_module); |