12573a464SChuck Lever // SPDX-License-Identifier: BSD-3-Clause 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/net/sunrpc/gss_krb5_mech.c 41da177e4SLinus Torvalds * 581d4a433SKevin Coffman * Copyright (c) 2001-2008 The Regents of the University of Michigan. 61da177e4SLinus Torvalds * All rights reserved. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Andy Adamson <andros@umich.edu> 91da177e4SLinus Torvalds * J. Bruce Fields <bfields@umich.edu> 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 123b5cf20cSHerbert Xu #include <crypto/hash.h> 133b5cf20cSHerbert Xu #include <crypto/skcipher.h> 14378c6697SHerbert Xu #include <linux/err.h> 151da177e4SLinus Torvalds #include <linux/module.h> 161da177e4SLinus Torvalds #include <linux/init.h> 171da177e4SLinus Torvalds #include <linux/types.h> 181da177e4SLinus Torvalds #include <linux/slab.h> 191da177e4SLinus Torvalds #include <linux/sunrpc/auth.h> 201da177e4SLinus Torvalds #include <linux/sunrpc/gss_krb5.h> 211da177e4SLinus Torvalds #include <linux/sunrpc/xdr.h> 22b084f598SJ. Bruce Fields #include <linux/sunrpc/gss_krb5_enctypes.h> 231da177e4SLinus Torvalds 24ba6dfce4SDave Wysochanski #include "auth_gss_internal.h" 25ba6dfce4SDave Wysochanski 26f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 271da177e4SLinus Torvalds # define RPCDBG_FACILITY RPCDBG_AUTH 281da177e4SLinus Torvalds #endif 291da177e4SLinus Torvalds 3047d84807SKevin Coffman static struct gss_api_mech gss_kerberos_mech; /* forward declaration */ 3147d84807SKevin Coffman 3281d4a433SKevin Coffman static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { 33fe9a2705SChuck Lever #ifndef CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES 3481d4a433SKevin Coffman /* 3581d4a433SKevin Coffman * DES (All DES enctypes are mapped to the same gss functionality) 3681d4a433SKevin Coffman */ 3781d4a433SKevin Coffman { 3881d4a433SKevin Coffman .etype = ENCTYPE_DES_CBC_RAW, 3981d4a433SKevin Coffman .ctype = CKSUMTYPE_RSA_MD5, 4081d4a433SKevin Coffman .name = "des-cbc-crc", 4181d4a433SKevin Coffman .encrypt_name = "cbc(des)", 4281d4a433SKevin Coffman .cksum_name = "md5", 4381d4a433SKevin Coffman .encrypt = krb5_encrypt, 4481d4a433SKevin Coffman .decrypt = krb5_decrypt, 454891f2d0SKevin Coffman .mk_key = NULL, 4681d4a433SKevin Coffman .signalg = SGN_ALG_DES_MAC_MD5, 4781d4a433SKevin Coffman .sealalg = SEAL_ALG_DES, 4881d4a433SKevin Coffman .keybytes = 7, 4981d4a433SKevin Coffman .keylength = 8, 5081d4a433SKevin Coffman .cksumlength = 8, 51e1f6c07bSKevin Coffman .keyed_cksum = 0, 5281d4a433SKevin Coffman }, 53fe9a2705SChuck Lever #endif /* CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES */ 54958142e9SKevin Coffman /* 55958142e9SKevin Coffman * 3DES 56958142e9SKevin Coffman */ 57958142e9SKevin Coffman { 58958142e9SKevin Coffman .etype = ENCTYPE_DES3_CBC_RAW, 59958142e9SKevin Coffman .ctype = CKSUMTYPE_HMAC_SHA1_DES3, 60958142e9SKevin Coffman .name = "des3-hmac-sha1", 61958142e9SKevin Coffman .encrypt_name = "cbc(des3_ede)", 62958142e9SKevin Coffman .cksum_name = "hmac(sha1)", 63958142e9SKevin Coffman .encrypt = krb5_encrypt, 64958142e9SKevin Coffman .decrypt = krb5_decrypt, 65958142e9SKevin Coffman .mk_key = gss_krb5_des3_make_key, 66958142e9SKevin Coffman .signalg = SGN_ALG_HMAC_SHA1_DES3_KD, 67958142e9SKevin Coffman .sealalg = SEAL_ALG_DES3KD, 68958142e9SKevin Coffman .keybytes = 21, 69958142e9SKevin Coffman .keylength = 24, 70958142e9SKevin Coffman .cksumlength = 20, 71958142e9SKevin Coffman .keyed_cksum = 1, 72958142e9SKevin Coffman }, 73934a95aaSKevin Coffman /* 74934a95aaSKevin Coffman * AES128 75934a95aaSKevin Coffman */ 76934a95aaSKevin Coffman { 77934a95aaSKevin Coffman .etype = ENCTYPE_AES128_CTS_HMAC_SHA1_96, 78934a95aaSKevin Coffman .ctype = CKSUMTYPE_HMAC_SHA1_96_AES128, 79934a95aaSKevin Coffman .name = "aes128-cts", 80934a95aaSKevin Coffman .encrypt_name = "cts(cbc(aes))", 817989a4f4SChuck Lever .aux_cipher = "cbc(aes)", 82934a95aaSKevin Coffman .cksum_name = "hmac(sha1)", 83934a95aaSKevin Coffman .encrypt = krb5_encrypt, 84934a95aaSKevin Coffman .decrypt = krb5_decrypt, 85934a95aaSKevin Coffman .mk_key = gss_krb5_aes_make_key, 86934a95aaSKevin Coffman .encrypt_v2 = gss_krb5_aes_encrypt, 87934a95aaSKevin Coffman .decrypt_v2 = gss_krb5_aes_decrypt, 88934a95aaSKevin Coffman .signalg = -1, 89934a95aaSKevin Coffman .sealalg = -1, 90934a95aaSKevin Coffman .keybytes = 16, 91934a95aaSKevin Coffman .keylength = 16, 92934a95aaSKevin Coffman .cksumlength = 12, 93934a95aaSKevin Coffman .keyed_cksum = 1, 94934a95aaSKevin Coffman }, 95934a95aaSKevin Coffman /* 96934a95aaSKevin Coffman * AES256 97934a95aaSKevin Coffman */ 98934a95aaSKevin Coffman { 99934a95aaSKevin Coffman .etype = ENCTYPE_AES256_CTS_HMAC_SHA1_96, 100934a95aaSKevin Coffman .ctype = CKSUMTYPE_HMAC_SHA1_96_AES256, 101934a95aaSKevin Coffman .name = "aes256-cts", 102934a95aaSKevin Coffman .encrypt_name = "cts(cbc(aes))", 1037989a4f4SChuck Lever .aux_cipher = "cbc(aes)", 104934a95aaSKevin Coffman .cksum_name = "hmac(sha1)", 105934a95aaSKevin Coffman .encrypt = krb5_encrypt, 106934a95aaSKevin Coffman .decrypt = krb5_decrypt, 107934a95aaSKevin Coffman .mk_key = gss_krb5_aes_make_key, 108934a95aaSKevin Coffman .encrypt_v2 = gss_krb5_aes_encrypt, 109934a95aaSKevin Coffman .decrypt_v2 = gss_krb5_aes_decrypt, 110934a95aaSKevin Coffman .signalg = -1, 111934a95aaSKevin Coffman .sealalg = -1, 112934a95aaSKevin Coffman .keybytes = 32, 113934a95aaSKevin Coffman .keylength = 32, 114934a95aaSKevin Coffman .cksumlength = 12, 115934a95aaSKevin Coffman .keyed_cksum = 1, 116934a95aaSKevin Coffman }, 11781d4a433SKevin Coffman }; 11881d4a433SKevin Coffman 11981d4a433SKevin Coffman static const int num_supported_enctypes = 12081d4a433SKevin Coffman ARRAY_SIZE(supported_gss_krb5_enctypes); 12181d4a433SKevin Coffman 12281d4a433SKevin Coffman static int 12381d4a433SKevin Coffman supported_gss_krb5_enctype(int etype) 12481d4a433SKevin Coffman { 12581d4a433SKevin Coffman int i; 12681d4a433SKevin Coffman for (i = 0; i < num_supported_enctypes; i++) 12781d4a433SKevin Coffman if (supported_gss_krb5_enctypes[i].etype == etype) 12881d4a433SKevin Coffman return 1; 12981d4a433SKevin Coffman return 0; 13081d4a433SKevin Coffman } 13181d4a433SKevin Coffman 13281d4a433SKevin Coffman static const struct gss_krb5_enctype * 13381d4a433SKevin Coffman get_gss_krb5_enctype(int etype) 13481d4a433SKevin Coffman { 13581d4a433SKevin Coffman int i; 13681d4a433SKevin Coffman for (i = 0; i < num_supported_enctypes; i++) 13781d4a433SKevin Coffman if (supported_gss_krb5_enctypes[i].etype == etype) 13881d4a433SKevin Coffman return &supported_gss_krb5_enctypes[i]; 13981d4a433SKevin Coffman return NULL; 14081d4a433SKevin Coffman } 14181d4a433SKevin Coffman 1421da177e4SLinus Torvalds static inline const void * 14381d4a433SKevin Coffman get_key(const void *p, const void *end, 144e9e575b8SKees Cook struct krb5_ctx *ctx, struct crypto_sync_skcipher **res) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds struct xdr_netobj key; 147378c6697SHerbert Xu int alg; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds p = simple_get_bytes(p, end, &alg, sizeof(alg)); 1501da177e4SLinus Torvalds if (IS_ERR(p)) 1511da177e4SLinus Torvalds goto out_err; 15281d4a433SKevin Coffman 15381d4a433SKevin Coffman switch (alg) { 15481d4a433SKevin Coffman case ENCTYPE_DES_CBC_CRC: 15581d4a433SKevin Coffman case ENCTYPE_DES_CBC_MD4: 15681d4a433SKevin Coffman case ENCTYPE_DES_CBC_MD5: 15781d4a433SKevin Coffman /* Map all these key types to ENCTYPE_DES_CBC_RAW */ 15881d4a433SKevin Coffman alg = ENCTYPE_DES_CBC_RAW; 15981d4a433SKevin Coffman break; 16081d4a433SKevin Coffman } 16181d4a433SKevin Coffman 16281d4a433SKevin Coffman if (!supported_gss_krb5_enctype(alg)) { 16381d4a433SKevin Coffman printk(KERN_WARNING "gss_kerberos_mech: unsupported " 16481d4a433SKevin Coffman "encryption key algorithm %d\n", alg); 165ce8477e1SBian Naimeng p = ERR_PTR(-EINVAL); 16681d4a433SKevin Coffman goto out_err; 16781d4a433SKevin Coffman } 1681da177e4SLinus Torvalds p = simple_get_netobj(p, end, &key); 1691da177e4SLinus Torvalds if (IS_ERR(p)) 1701da177e4SLinus Torvalds goto out_err; 1711da177e4SLinus Torvalds 172e9e575b8SKees Cook *res = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0); 173378c6697SHerbert Xu if (IS_ERR(*res)) { 17481d4a433SKevin Coffman printk(KERN_WARNING "gss_kerberos_mech: unable to initialize " 17581d4a433SKevin Coffman "crypto algorithm %s\n", ctx->gk5e->encrypt_name); 176378c6697SHerbert Xu *res = NULL; 1771da177e4SLinus Torvalds goto out_err_free_key; 1789e56904eSJ. Bruce Fields } 179e9e575b8SKees Cook if (crypto_sync_skcipher_setkey(*res, key.data, key.len)) { 18081d4a433SKevin Coffman printk(KERN_WARNING "gss_kerberos_mech: error setting key for " 18181d4a433SKevin Coffman "crypto algorithm %s\n", ctx->gk5e->encrypt_name); 1821da177e4SLinus Torvalds goto out_err_free_tfm; 1839e56904eSJ. Bruce Fields } 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds kfree(key.data); 1861da177e4SLinus Torvalds return p; 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds out_err_free_tfm: 189e9e575b8SKees Cook crypto_free_sync_skcipher(*res); 1901da177e4SLinus Torvalds out_err_free_key: 1911da177e4SLinus Torvalds kfree(key.data); 1921da177e4SLinus Torvalds p = ERR_PTR(-EINVAL); 1931da177e4SLinus Torvalds out_err: 1941da177e4SLinus Torvalds return p; 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds static int 198a8cc1cb7SKevin Coffman gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx) 1991da177e4SLinus Torvalds { 200c3be6577SPaul Burton u32 seq_send; 201e678e06bSJ. Bruce Fields int tmp; 202294ec5b8SArnd Bergmann u32 time32; 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); 2051da177e4SLinus Torvalds if (IS_ERR(p)) 206a8cc1cb7SKevin Coffman goto out_err; 207a8cc1cb7SKevin Coffman 208a8cc1cb7SKevin Coffman /* Old format supports only DES! Any other enctype uses new format */ 2091ac3719aSKevin Coffman ctx->enctype = ENCTYPE_DES_CBC_RAW; 210a8cc1cb7SKevin Coffman 21181d4a433SKevin Coffman ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); 212ce8477e1SBian Naimeng if (ctx->gk5e == NULL) { 213ce8477e1SBian Naimeng p = ERR_PTR(-EINVAL); 21481d4a433SKevin Coffman goto out_err; 215ce8477e1SBian Naimeng } 21681d4a433SKevin Coffman 217717757adSJ. Bruce Fields /* The downcall format was designed before we completely understood 218717757adSJ. Bruce Fields * the uses of the context fields; so it includes some stuff we 219717757adSJ. Bruce Fields * just give some minimal sanity-checking, and some we ignore 220717757adSJ. Bruce Fields * completely (like the next twenty bytes): */ 221ce8477e1SBian Naimeng if (unlikely(p + 20 > end || p + 20 < p)) { 222ce8477e1SBian Naimeng p = ERR_PTR(-EFAULT); 223a8cc1cb7SKevin Coffman goto out_err; 224ce8477e1SBian Naimeng } 225717757adSJ. Bruce Fields p += 20; 226e678e06bSJ. Bruce Fields p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); 2271da177e4SLinus Torvalds if (IS_ERR(p)) 228a8cc1cb7SKevin Coffman goto out_err; 229ef338beeSKevin Coffman if (tmp != SGN_ALG_DES_MAC_MD5) { 230ef338beeSKevin Coffman p = ERR_PTR(-ENOSYS); 231a8cc1cb7SKevin Coffman goto out_err; 232ef338beeSKevin Coffman } 233d922a84aSJ. Bruce Fields p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); 2341da177e4SLinus Torvalds if (IS_ERR(p)) 235a8cc1cb7SKevin Coffman goto out_err; 236ef338beeSKevin Coffman if (tmp != SEAL_ALG_DES) { 237ef338beeSKevin Coffman p = ERR_PTR(-ENOSYS); 238a8cc1cb7SKevin Coffman goto out_err; 239ef338beeSKevin Coffman } 240294ec5b8SArnd Bergmann p = simple_get_bytes(p, end, &time32, sizeof(time32)); 2411da177e4SLinus Torvalds if (IS_ERR(p)) 242a8cc1cb7SKevin Coffman goto out_err; 243294ec5b8SArnd Bergmann /* unsigned 32-bit time overflows in year 2106 */ 244294ec5b8SArnd Bergmann ctx->endtime = (time64_t)time32; 245c3be6577SPaul Burton p = simple_get_bytes(p, end, &seq_send, sizeof(seq_send)); 2461da177e4SLinus Torvalds if (IS_ERR(p)) 247a8cc1cb7SKevin Coffman goto out_err; 248c3be6577SPaul Burton atomic_set(&ctx->seq_send, seq_send); 2491da177e4SLinus Torvalds p = simple_get_netobj(p, end, &ctx->mech_used); 2501da177e4SLinus Torvalds if (IS_ERR(p)) 251a8cc1cb7SKevin Coffman goto out_err; 25281d4a433SKevin Coffman p = get_key(p, end, ctx, &ctx->enc); 2531da177e4SLinus Torvalds if (IS_ERR(p)) 2541da177e4SLinus Torvalds goto out_err_free_mech; 25581d4a433SKevin Coffman p = get_key(p, end, ctx, &ctx->seq); 2561da177e4SLinus Torvalds if (IS_ERR(p)) 2571da177e4SLinus Torvalds goto out_err_free_key1; 2581da177e4SLinus Torvalds if (p != end) { 2591da177e4SLinus Torvalds p = ERR_PTR(-EFAULT); 2601da177e4SLinus Torvalds goto out_err_free_key2; 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds return 0; 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds out_err_free_key2: 266e9e575b8SKees Cook crypto_free_sync_skcipher(ctx->seq); 2671da177e4SLinus Torvalds out_err_free_key1: 268e9e575b8SKees Cook crypto_free_sync_skcipher(ctx->enc); 2691da177e4SLinus Torvalds out_err_free_mech: 2701da177e4SLinus Torvalds kfree(ctx->mech_used.data); 2711da177e4SLinus Torvalds out_err: 2721da177e4SLinus Torvalds return PTR_ERR(p); 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 275e9e575b8SKees Cook static struct crypto_sync_skcipher * 276934a95aaSKevin Coffman context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key) 27747d84807SKevin Coffman { 278e9e575b8SKees Cook struct crypto_sync_skcipher *cp; 27947d84807SKevin Coffman 280e9e575b8SKees Cook cp = crypto_alloc_sync_skcipher(cname, 0, 0); 28147d84807SKevin Coffman if (IS_ERR(cp)) { 28247d84807SKevin Coffman dprintk("gss_kerberos_mech: unable to initialize " 283934a95aaSKevin Coffman "crypto algorithm %s\n", cname); 28447d84807SKevin Coffman return NULL; 28547d84807SKevin Coffman } 286e9e575b8SKees Cook if (crypto_sync_skcipher_setkey(cp, key, ctx->gk5e->keylength)) { 28747d84807SKevin Coffman dprintk("gss_kerberos_mech: error setting key for " 288934a95aaSKevin Coffman "crypto algorithm %s\n", cname); 289e9e575b8SKees Cook crypto_free_sync_skcipher(cp); 29047d84807SKevin Coffman return NULL; 29147d84807SKevin Coffman } 29247d84807SKevin Coffman return cp; 29347d84807SKevin Coffman } 29447d84807SKevin Coffman 29547d84807SKevin Coffman static inline void 29647d84807SKevin Coffman set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed) 29747d84807SKevin Coffman { 29847d84807SKevin Coffman cdata[0] = (usage>>24)&0xff; 29947d84807SKevin Coffman cdata[1] = (usage>>16)&0xff; 30047d84807SKevin Coffman cdata[2] = (usage>>8)&0xff; 30147d84807SKevin Coffman cdata[3] = usage&0xff; 30247d84807SKevin Coffman cdata[4] = seed; 30347d84807SKevin Coffman } 30447d84807SKevin Coffman 30547d84807SKevin Coffman static int 3061f4c86c0STrond Myklebust context_derive_keys_des3(struct krb5_ctx *ctx, gfp_t gfp_mask) 30747d84807SKevin Coffman { 30847d84807SKevin Coffman struct xdr_netobj c, keyin, keyout; 30947d84807SKevin Coffman u8 cdata[GSS_KRB5_K5CLENGTH]; 31047d84807SKevin Coffman u32 err; 31147d84807SKevin Coffman 31247d84807SKevin Coffman c.len = GSS_KRB5_K5CLENGTH; 31347d84807SKevin Coffman c.data = cdata; 31447d84807SKevin Coffman 315fc263a91SKevin Coffman keyin.data = ctx->Ksess; 316fc263a91SKevin Coffman keyin.len = ctx->gk5e->keylength; 317fc263a91SKevin Coffman keyout.len = ctx->gk5e->keylength; 31847d84807SKevin Coffman 31947d84807SKevin Coffman /* seq uses the raw key */ 320934a95aaSKevin Coffman ctx->seq = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, 321fc263a91SKevin Coffman ctx->Ksess); 32247d84807SKevin Coffman if (ctx->seq == NULL) 32347d84807SKevin Coffman goto out_err; 32447d84807SKevin Coffman 325934a95aaSKevin Coffman ctx->enc = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, 326fc263a91SKevin Coffman ctx->Ksess); 32747d84807SKevin Coffman if (ctx->enc == NULL) 32847d84807SKevin Coffman goto out_free_seq; 32947d84807SKevin Coffman 33047d84807SKevin Coffman /* derive cksum */ 33147d84807SKevin Coffman set_cdata(cdata, KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM); 33247d84807SKevin Coffman keyout.data = ctx->cksum; 3331f4c86c0STrond Myklebust err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 33447d84807SKevin Coffman if (err) { 33547d84807SKevin Coffman dprintk("%s: Error %d deriving cksum key\n", 33647d84807SKevin Coffman __func__, err); 33747d84807SKevin Coffman goto out_free_enc; 33847d84807SKevin Coffman } 33947d84807SKevin Coffman 34047d84807SKevin Coffman return 0; 34147d84807SKevin Coffman 34247d84807SKevin Coffman out_free_enc: 343e9e575b8SKees Cook crypto_free_sync_skcipher(ctx->enc); 34447d84807SKevin Coffman out_free_seq: 345e9e575b8SKees Cook crypto_free_sync_skcipher(ctx->seq); 34647d84807SKevin Coffman out_err: 34747d84807SKevin Coffman return -EINVAL; 34847d84807SKevin Coffman } 34947d84807SKevin Coffman 3502dbe0cacSChuck Lever static struct crypto_ahash * 3512dbe0cacSChuck Lever gss_krb5_alloc_hash_v2(struct krb5_ctx *kctx, const struct xdr_netobj *key) 3522dbe0cacSChuck Lever { 3532dbe0cacSChuck Lever struct crypto_ahash *tfm; 3542dbe0cacSChuck Lever 3552dbe0cacSChuck Lever tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); 3562dbe0cacSChuck Lever if (IS_ERR(tfm)) 3572dbe0cacSChuck Lever return NULL; 3582dbe0cacSChuck Lever if (crypto_ahash_setkey(tfm, key->data, key->len)) { 3592dbe0cacSChuck Lever crypto_free_ahash(tfm); 3602dbe0cacSChuck Lever return NULL; 3612dbe0cacSChuck Lever } 3622dbe0cacSChuck Lever return tfm; 3632dbe0cacSChuck Lever } 3642dbe0cacSChuck Lever 36547d84807SKevin Coffman static int 3661f4c86c0STrond Myklebust context_derive_keys_new(struct krb5_ctx *ctx, gfp_t gfp_mask) 36747d84807SKevin Coffman { 36847d84807SKevin Coffman u8 cdata[GSS_KRB5_K5CLENGTH]; 3699f0b49f9SChuck Lever struct xdr_netobj c = { 3709f0b49f9SChuck Lever .len = sizeof(cdata), 3719f0b49f9SChuck Lever .data = cdata, 3729f0b49f9SChuck Lever }; 3739f0b49f9SChuck Lever struct xdr_netobj keyin = { 3749f0b49f9SChuck Lever .len = ctx->gk5e->keylength, 3759f0b49f9SChuck Lever .data = ctx->Ksess, 3769f0b49f9SChuck Lever }; 3779f0b49f9SChuck Lever struct xdr_netobj keyout; 3789f0b49f9SChuck Lever int ret = -EINVAL; 3799f0b49f9SChuck Lever void *subkey; 38047d84807SKevin Coffman u32 err; 38147d84807SKevin Coffman 3829f0b49f9SChuck Lever subkey = kmalloc(ctx->gk5e->keylength, gfp_mask); 3839f0b49f9SChuck Lever if (!subkey) 3849f0b49f9SChuck Lever return -ENOMEM; 385fc263a91SKevin Coffman keyout.len = ctx->gk5e->keylength; 3869f0b49f9SChuck Lever keyout.data = subkey; 38747d84807SKevin Coffman 38847d84807SKevin Coffman /* initiator seal encryption */ 38947d84807SKevin Coffman set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); 3901f4c86c0STrond Myklebust err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 39147d84807SKevin Coffman if (err) { 39247d84807SKevin Coffman dprintk("%s: Error %d deriving initiator_seal key\n", 39347d84807SKevin Coffman __func__, err); 3949f0b49f9SChuck Lever goto out; 39547d84807SKevin Coffman } 396934a95aaSKevin Coffman ctx->initiator_enc = context_v2_alloc_cipher(ctx, 397934a95aaSKevin Coffman ctx->gk5e->encrypt_name, 3989f0b49f9SChuck Lever subkey); 39947d84807SKevin Coffman if (ctx->initiator_enc == NULL) 4009f0b49f9SChuck Lever goto out; 4017989a4f4SChuck Lever if (ctx->gk5e->aux_cipher) { 4027989a4f4SChuck Lever ctx->initiator_enc_aux = 4037989a4f4SChuck Lever context_v2_alloc_cipher(ctx, ctx->gk5e->aux_cipher, 4049f0b49f9SChuck Lever subkey); 4057989a4f4SChuck Lever if (ctx->initiator_enc_aux == NULL) 4067989a4f4SChuck Lever goto out_free; 4077989a4f4SChuck Lever } 40847d84807SKevin Coffman 40947d84807SKevin Coffman /* acceptor seal encryption */ 41047d84807SKevin Coffman set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); 4111f4c86c0STrond Myklebust err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 41247d84807SKevin Coffman if (err) { 41347d84807SKevin Coffman dprintk("%s: Error %d deriving acceptor_seal key\n", 41447d84807SKevin Coffman __func__, err); 4157989a4f4SChuck Lever goto out_free; 41647d84807SKevin Coffman } 417934a95aaSKevin Coffman ctx->acceptor_enc = context_v2_alloc_cipher(ctx, 418934a95aaSKevin Coffman ctx->gk5e->encrypt_name, 4199f0b49f9SChuck Lever subkey); 42047d84807SKevin Coffman if (ctx->acceptor_enc == NULL) 4217989a4f4SChuck Lever goto out_free; 4227989a4f4SChuck Lever if (ctx->gk5e->aux_cipher) { 4237989a4f4SChuck Lever ctx->acceptor_enc_aux = 4247989a4f4SChuck Lever context_v2_alloc_cipher(ctx, ctx->gk5e->aux_cipher, 4259f0b49f9SChuck Lever subkey); 4267989a4f4SChuck Lever if (ctx->acceptor_enc_aux == NULL) 4277989a4f4SChuck Lever goto out_free; 4287989a4f4SChuck Lever } 42947d84807SKevin Coffman 43047d84807SKevin Coffman /* initiator sign checksum */ 43147d84807SKevin Coffman set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM); 4321f4c86c0STrond Myklebust err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 4332dbe0cacSChuck Lever if (err) 4347989a4f4SChuck Lever goto out_free; 4352dbe0cacSChuck Lever ctx->initiator_sign = gss_krb5_alloc_hash_v2(ctx, &keyout); 4362dbe0cacSChuck Lever if (ctx->initiator_sign == NULL) 4372dbe0cacSChuck Lever goto out_free; 43847d84807SKevin Coffman 43947d84807SKevin Coffman /* acceptor sign checksum */ 44047d84807SKevin Coffman set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM); 4411f4c86c0STrond Myklebust err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 4422dbe0cacSChuck Lever if (err) 4437989a4f4SChuck Lever goto out_free; 4442dbe0cacSChuck Lever ctx->acceptor_sign = gss_krb5_alloc_hash_v2(ctx, &keyout); 4452dbe0cacSChuck Lever if (ctx->acceptor_sign == NULL) 4462dbe0cacSChuck Lever goto out_free; 44747d84807SKevin Coffman 44847d84807SKevin Coffman /* initiator seal integrity */ 44947d84807SKevin Coffman set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY); 4501f4c86c0STrond Myklebust err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 451*8270dbfcSChuck Lever if (err) 4527989a4f4SChuck Lever goto out_free; 453*8270dbfcSChuck Lever ctx->initiator_integ = gss_krb5_alloc_hash_v2(ctx, &keyout); 454*8270dbfcSChuck Lever if (ctx->initiator_integ == NULL) 455*8270dbfcSChuck Lever goto out_free; 45647d84807SKevin Coffman 45747d84807SKevin Coffman /* acceptor seal integrity */ 45847d84807SKevin Coffman set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_INTEGRITY); 4591f4c86c0STrond Myklebust err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 460*8270dbfcSChuck Lever if (err) 4617989a4f4SChuck Lever goto out_free; 462*8270dbfcSChuck Lever ctx->acceptor_integ = gss_krb5_alloc_hash_v2(ctx, &keyout); 463*8270dbfcSChuck Lever if (ctx->acceptor_integ == NULL) 464*8270dbfcSChuck Lever goto out_free; 465934a95aaSKevin Coffman 4669f0b49f9SChuck Lever ret = 0; 4679f0b49f9SChuck Lever out: 4689f0b49f9SChuck Lever kfree_sensitive(subkey); 4699f0b49f9SChuck Lever return ret; 47047d84807SKevin Coffman 4717989a4f4SChuck Lever out_free: 472*8270dbfcSChuck Lever crypto_free_ahash(ctx->acceptor_integ); 473*8270dbfcSChuck Lever crypto_free_ahash(ctx->initiator_integ); 4742dbe0cacSChuck Lever crypto_free_ahash(ctx->acceptor_sign); 4752dbe0cacSChuck Lever crypto_free_ahash(ctx->initiator_sign); 4767989a4f4SChuck Lever crypto_free_sync_skcipher(ctx->acceptor_enc_aux); 477e9e575b8SKees Cook crypto_free_sync_skcipher(ctx->acceptor_enc); 4787989a4f4SChuck Lever crypto_free_sync_skcipher(ctx->initiator_enc_aux); 479e9e575b8SKees Cook crypto_free_sync_skcipher(ctx->initiator_enc); 4809f0b49f9SChuck Lever goto out; 48147d84807SKevin Coffman } 48247d84807SKevin Coffman 48347d84807SKevin Coffman static int 4841f4c86c0STrond Myklebust gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx, 4851f4c86c0STrond Myklebust gfp_t gfp_mask) 48647d84807SKevin Coffman { 487c3be6577SPaul Burton u64 seq_send64; 48847d84807SKevin Coffman int keylen; 489294ec5b8SArnd Bergmann u32 time32; 49047d84807SKevin Coffman 49147d84807SKevin Coffman p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags)); 49247d84807SKevin Coffman if (IS_ERR(p)) 49347d84807SKevin Coffman goto out_err; 49447d84807SKevin Coffman ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR; 49547d84807SKevin Coffman 496294ec5b8SArnd Bergmann p = simple_get_bytes(p, end, &time32, sizeof(time32)); 49747d84807SKevin Coffman if (IS_ERR(p)) 49847d84807SKevin Coffman goto out_err; 499294ec5b8SArnd Bergmann /* unsigned 32-bit time overflows in year 2106 */ 500294ec5b8SArnd Bergmann ctx->endtime = (time64_t)time32; 501c3be6577SPaul Burton p = simple_get_bytes(p, end, &seq_send64, sizeof(seq_send64)); 50247d84807SKevin Coffman if (IS_ERR(p)) 50347d84807SKevin Coffman goto out_err; 504c3be6577SPaul Burton atomic64_set(&ctx->seq_send64, seq_send64); 50547d84807SKevin Coffman /* set seq_send for use by "older" enctypes */ 506c3be6577SPaul Burton atomic_set(&ctx->seq_send, seq_send64); 507c3be6577SPaul Burton if (seq_send64 != atomic_read(&ctx->seq_send)) { 508c3be6577SPaul Burton dprintk("%s: seq_send64 %llx, seq_send %x overflow?\n", __func__, 509c3be6577SPaul Burton seq_send64, atomic_read(&ctx->seq_send)); 510ce8477e1SBian Naimeng p = ERR_PTR(-EINVAL); 51147d84807SKevin Coffman goto out_err; 51247d84807SKevin Coffman } 51347d84807SKevin Coffman p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype)); 51447d84807SKevin Coffman if (IS_ERR(p)) 51547d84807SKevin Coffman goto out_err; 516958142e9SKevin Coffman /* Map ENCTYPE_DES3_CBC_SHA1 to ENCTYPE_DES3_CBC_RAW */ 517958142e9SKevin Coffman if (ctx->enctype == ENCTYPE_DES3_CBC_SHA1) 518958142e9SKevin Coffman ctx->enctype = ENCTYPE_DES3_CBC_RAW; 51947d84807SKevin Coffman ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); 52047d84807SKevin Coffman if (ctx->gk5e == NULL) { 52147d84807SKevin Coffman dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n", 52247d84807SKevin Coffman ctx->enctype); 52347d84807SKevin Coffman p = ERR_PTR(-EINVAL); 52447d84807SKevin Coffman goto out_err; 52547d84807SKevin Coffman } 52647d84807SKevin Coffman keylen = ctx->gk5e->keylength; 52747d84807SKevin Coffman 528fc263a91SKevin Coffman p = simple_get_bytes(p, end, ctx->Ksess, keylen); 52947d84807SKevin Coffman if (IS_ERR(p)) 53047d84807SKevin Coffman goto out_err; 53147d84807SKevin Coffman 53247d84807SKevin Coffman if (p != end) { 53347d84807SKevin Coffman p = ERR_PTR(-EINVAL); 53447d84807SKevin Coffman goto out_err; 53547d84807SKevin Coffman } 53647d84807SKevin Coffman 53747d84807SKevin Coffman ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data, 5381f4c86c0STrond Myklebust gss_kerberos_mech.gm_oid.len, gfp_mask); 53947d84807SKevin Coffman if (unlikely(ctx->mech_used.data == NULL)) { 54047d84807SKevin Coffman p = ERR_PTR(-ENOMEM); 54147d84807SKevin Coffman goto out_err; 54247d84807SKevin Coffman } 54347d84807SKevin Coffman ctx->mech_used.len = gss_kerberos_mech.gm_oid.len; 54447d84807SKevin Coffman 54547d84807SKevin Coffman switch (ctx->enctype) { 54647d84807SKevin Coffman case ENCTYPE_DES3_CBC_RAW: 5471f4c86c0STrond Myklebust return context_derive_keys_des3(ctx, gfp_mask); 54847d84807SKevin Coffman case ENCTYPE_AES128_CTS_HMAC_SHA1_96: 54947d84807SKevin Coffman case ENCTYPE_AES256_CTS_HMAC_SHA1_96: 5501f4c86c0STrond Myklebust return context_derive_keys_new(ctx, gfp_mask); 55147d84807SKevin Coffman default: 55247d84807SKevin Coffman return -EINVAL; 55347d84807SKevin Coffman } 55447d84807SKevin Coffman 55547d84807SKevin Coffman out_err: 55647d84807SKevin Coffman return PTR_ERR(p); 55747d84807SKevin Coffman } 55847d84807SKevin Coffman 559a8cc1cb7SKevin Coffman static int 560a8cc1cb7SKevin Coffman gss_import_sec_context_kerberos(const void *p, size_t len, 5611f4c86c0STrond Myklebust struct gss_ctx *ctx_id, 562294ec5b8SArnd Bergmann time64_t *endtime, 5631f4c86c0STrond Myklebust gfp_t gfp_mask) 564a8cc1cb7SKevin Coffman { 565a8cc1cb7SKevin Coffman const void *end = (const void *)((const char *)p + len); 566a8cc1cb7SKevin Coffman struct krb5_ctx *ctx; 567a8cc1cb7SKevin Coffman int ret; 568a8cc1cb7SKevin Coffman 5691f4c86c0STrond Myklebust ctx = kzalloc(sizeof(*ctx), gfp_mask); 570a8cc1cb7SKevin Coffman if (ctx == NULL) 571a8cc1cb7SKevin Coffman return -ENOMEM; 572a8cc1cb7SKevin Coffman 573a8cc1cb7SKevin Coffman if (len == 85) 574a8cc1cb7SKevin Coffman ret = gss_import_v1_context(p, end, ctx); 575a8cc1cb7SKevin Coffman else 5761f4c86c0STrond Myklebust ret = gss_import_v2_context(p, end, ctx, gfp_mask); 57701c4e326SChuck Lever memzero_explicit(&ctx->Ksess, sizeof(ctx->Ksess)); 5787f675ca7SChuck Lever if (ret) { 5797f675ca7SChuck Lever kfree(ctx); 5807f675ca7SChuck Lever return ret; 5817f675ca7SChuck Lever } 582a8cc1cb7SKevin Coffman 583a8cc1cb7SKevin Coffman ctx_id->internal_ctx_id = ctx; 584400f26b5SSimo Sorce if (endtime) 585400f26b5SSimo Sorce *endtime = ctx->endtime; 5867f675ca7SChuck Lever return 0; 587a8cc1cb7SKevin Coffman } 588a8cc1cb7SKevin Coffman 5891da177e4SLinus Torvalds static void 5901da177e4SLinus Torvalds gss_delete_sec_context_kerberos(void *internal_ctx) { 5911da177e4SLinus Torvalds struct krb5_ctx *kctx = internal_ctx; 5921da177e4SLinus Torvalds 593e9e575b8SKees Cook crypto_free_sync_skcipher(kctx->seq); 594e9e575b8SKees Cook crypto_free_sync_skcipher(kctx->enc); 595e9e575b8SKees Cook crypto_free_sync_skcipher(kctx->acceptor_enc); 596e9e575b8SKees Cook crypto_free_sync_skcipher(kctx->initiator_enc); 597e9e575b8SKees Cook crypto_free_sync_skcipher(kctx->acceptor_enc_aux); 598e9e575b8SKees Cook crypto_free_sync_skcipher(kctx->initiator_enc_aux); 5992dbe0cacSChuck Lever crypto_free_ahash(kctx->acceptor_sign); 6002dbe0cacSChuck Lever crypto_free_ahash(kctx->initiator_sign); 601*8270dbfcSChuck Lever crypto_free_ahash(kctx->acceptor_integ); 602*8270dbfcSChuck Lever crypto_free_ahash(kctx->initiator_integ); 6031da177e4SLinus Torvalds kfree(kctx->mech_used.data); 6041da177e4SLinus Torvalds kfree(kctx); 6051da177e4SLinus Torvalds } 6061da177e4SLinus Torvalds 607f1c0a861STrond Myklebust static const struct gss_api_ops gss_kerberos_ops = { 6081da177e4SLinus Torvalds .gss_import_sec_context = gss_import_sec_context_kerberos, 6091da177e4SLinus Torvalds .gss_get_mic = gss_get_mic_kerberos, 6101da177e4SLinus Torvalds .gss_verify_mic = gss_verify_mic_kerberos, 61114ae162cSJ. Bruce Fields .gss_wrap = gss_wrap_kerberos, 61214ae162cSJ. Bruce Fields .gss_unwrap = gss_unwrap_kerberos, 6131da177e4SLinus Torvalds .gss_delete_sec_context = gss_delete_sec_context_kerberos, 6141da177e4SLinus Torvalds }; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds static struct pf_desc gss_kerberos_pfs[] = { 6171da177e4SLinus Torvalds [0] = { 6181da177e4SLinus Torvalds .pseudoflavor = RPC_AUTH_GSS_KRB5, 61983523d08SChuck Lever .qop = GSS_C_QOP_DEFAULT, 6201da177e4SLinus Torvalds .service = RPC_GSS_SVC_NONE, 6211da177e4SLinus Torvalds .name = "krb5", 6221da177e4SLinus Torvalds }, 6231da177e4SLinus Torvalds [1] = { 6241da177e4SLinus Torvalds .pseudoflavor = RPC_AUTH_GSS_KRB5I, 62583523d08SChuck Lever .qop = GSS_C_QOP_DEFAULT, 6261da177e4SLinus Torvalds .service = RPC_GSS_SVC_INTEGRITY, 6271da177e4SLinus Torvalds .name = "krb5i", 62865b80179SChuck Lever .datatouch = true, 6291da177e4SLinus Torvalds }, 63014ae162cSJ. Bruce Fields [2] = { 63114ae162cSJ. Bruce Fields .pseudoflavor = RPC_AUTH_GSS_KRB5P, 63283523d08SChuck Lever .qop = GSS_C_QOP_DEFAULT, 63314ae162cSJ. Bruce Fields .service = RPC_GSS_SVC_PRIVACY, 63414ae162cSJ. Bruce Fields .name = "krb5p", 63565b80179SChuck Lever .datatouch = true, 63614ae162cSJ. Bruce Fields }, 6371da177e4SLinus Torvalds }; 6381da177e4SLinus Torvalds 639058c5c99SJ. Bruce Fields MODULE_ALIAS("rpc-auth-gss-krb5"); 640058c5c99SJ. Bruce Fields MODULE_ALIAS("rpc-auth-gss-krb5i"); 641058c5c99SJ. Bruce Fields MODULE_ALIAS("rpc-auth-gss-krb5p"); 642058c5c99SJ. Bruce Fields MODULE_ALIAS("rpc-auth-gss-390003"); 643058c5c99SJ. Bruce Fields MODULE_ALIAS("rpc-auth-gss-390004"); 644058c5c99SJ. Bruce Fields MODULE_ALIAS("rpc-auth-gss-390005"); 645f783288fSChuck Lever MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2"); 646058c5c99SJ. Bruce Fields 6471da177e4SLinus Torvalds static struct gss_api_mech gss_kerberos_mech = { 6481da177e4SLinus Torvalds .gm_name = "krb5", 6491da177e4SLinus Torvalds .gm_owner = THIS_MODULE, 650fb15b26fSChuck Lever .gm_oid = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }, 6511da177e4SLinus Torvalds .gm_ops = &gss_kerberos_ops, 6521da177e4SLinus Torvalds .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), 6531da177e4SLinus Torvalds .gm_pfs = gss_kerberos_pfs, 654b084f598SJ. Bruce Fields .gm_upcall_enctypes = KRB5_SUPPORTED_ENCTYPES, 6551da177e4SLinus Torvalds }; 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds static int __init init_kerberos_module(void) 6581da177e4SLinus Torvalds { 6591da177e4SLinus Torvalds int status; 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds status = gss_mech_register(&gss_kerberos_mech); 6621da177e4SLinus Torvalds if (status) 6631da177e4SLinus Torvalds printk("Failed to register kerberos gss mechanism!\n"); 6641da177e4SLinus Torvalds return status; 6651da177e4SLinus Torvalds } 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds static void __exit cleanup_kerberos_module(void) 6681da177e4SLinus Torvalds { 6691da177e4SLinus Torvalds gss_mech_unregister(&gss_kerberos_mech); 6701da177e4SLinus Torvalds } 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 6731da177e4SLinus Torvalds module_init(init_kerberos_module); 6741da177e4SLinus Torvalds module_exit(cleanup_kerberos_module); 675