162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/net/sunrpc/gss_krb5_mech.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2001-2008 The Regents of the University of Michigan. 662306a36Sopenharmony_ci * All rights reserved. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Andy Adamson <andros@umich.edu> 962306a36Sopenharmony_ci * J. Bruce Fields <bfields@umich.edu> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <crypto/hash.h> 1362306a36Sopenharmony_ci#include <crypto/skcipher.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/types.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/sunrpc/auth.h> 2062306a36Sopenharmony_ci#include <linux/sunrpc/gss_krb5.h> 2162306a36Sopenharmony_ci#include <linux/sunrpc/xdr.h> 2262306a36Sopenharmony_ci#include <kunit/visibility.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "auth_gss_internal.h" 2562306a36Sopenharmony_ci#include "gss_krb5_internal.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 2862306a36Sopenharmony_ci# define RPCDBG_FACILITY RPCDBG_AUTH 2962306a36Sopenharmony_ci#endif 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic struct gss_api_mech gss_kerberos_mech; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { 3462306a36Sopenharmony_ci#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1) 3562306a36Sopenharmony_ci /* 3662306a36Sopenharmony_ci * AES-128 with SHA-1 (RFC 3962) 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci { 3962306a36Sopenharmony_ci .etype = ENCTYPE_AES128_CTS_HMAC_SHA1_96, 4062306a36Sopenharmony_ci .ctype = CKSUMTYPE_HMAC_SHA1_96_AES128, 4162306a36Sopenharmony_ci .name = "aes128-cts", 4262306a36Sopenharmony_ci .encrypt_name = "cts(cbc(aes))", 4362306a36Sopenharmony_ci .aux_cipher = "cbc(aes)", 4462306a36Sopenharmony_ci .cksum_name = "hmac(sha1)", 4562306a36Sopenharmony_ci .derive_key = krb5_derive_key_v2, 4662306a36Sopenharmony_ci .encrypt = gss_krb5_aes_encrypt, 4762306a36Sopenharmony_ci .decrypt = gss_krb5_aes_decrypt, 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci .get_mic = gss_krb5_get_mic_v2, 5062306a36Sopenharmony_ci .verify_mic = gss_krb5_verify_mic_v2, 5162306a36Sopenharmony_ci .wrap = gss_krb5_wrap_v2, 5262306a36Sopenharmony_ci .unwrap = gss_krb5_unwrap_v2, 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci .signalg = -1, 5562306a36Sopenharmony_ci .sealalg = -1, 5662306a36Sopenharmony_ci .keybytes = 16, 5762306a36Sopenharmony_ci .keylength = BITS2OCTETS(128), 5862306a36Sopenharmony_ci .Kc_length = BITS2OCTETS(128), 5962306a36Sopenharmony_ci .Ke_length = BITS2OCTETS(128), 6062306a36Sopenharmony_ci .Ki_length = BITS2OCTETS(128), 6162306a36Sopenharmony_ci .cksumlength = BITS2OCTETS(96), 6262306a36Sopenharmony_ci .keyed_cksum = 1, 6362306a36Sopenharmony_ci }, 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * AES-256 with SHA-1 (RFC 3962) 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci { 6862306a36Sopenharmony_ci .etype = ENCTYPE_AES256_CTS_HMAC_SHA1_96, 6962306a36Sopenharmony_ci .ctype = CKSUMTYPE_HMAC_SHA1_96_AES256, 7062306a36Sopenharmony_ci .name = "aes256-cts", 7162306a36Sopenharmony_ci .encrypt_name = "cts(cbc(aes))", 7262306a36Sopenharmony_ci .aux_cipher = "cbc(aes)", 7362306a36Sopenharmony_ci .cksum_name = "hmac(sha1)", 7462306a36Sopenharmony_ci .derive_key = krb5_derive_key_v2, 7562306a36Sopenharmony_ci .encrypt = gss_krb5_aes_encrypt, 7662306a36Sopenharmony_ci .decrypt = gss_krb5_aes_decrypt, 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci .get_mic = gss_krb5_get_mic_v2, 7962306a36Sopenharmony_ci .verify_mic = gss_krb5_verify_mic_v2, 8062306a36Sopenharmony_ci .wrap = gss_krb5_wrap_v2, 8162306a36Sopenharmony_ci .unwrap = gss_krb5_unwrap_v2, 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci .signalg = -1, 8462306a36Sopenharmony_ci .sealalg = -1, 8562306a36Sopenharmony_ci .keybytes = 32, 8662306a36Sopenharmony_ci .keylength = BITS2OCTETS(256), 8762306a36Sopenharmony_ci .Kc_length = BITS2OCTETS(256), 8862306a36Sopenharmony_ci .Ke_length = BITS2OCTETS(256), 8962306a36Sopenharmony_ci .Ki_length = BITS2OCTETS(256), 9062306a36Sopenharmony_ci .cksumlength = BITS2OCTETS(96), 9162306a36Sopenharmony_ci .keyed_cksum = 1, 9262306a36Sopenharmony_ci }, 9362306a36Sopenharmony_ci#endif 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA) 9662306a36Sopenharmony_ci /* 9762306a36Sopenharmony_ci * Camellia-128 with CMAC (RFC 6803) 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci { 10062306a36Sopenharmony_ci .etype = ENCTYPE_CAMELLIA128_CTS_CMAC, 10162306a36Sopenharmony_ci .ctype = CKSUMTYPE_CMAC_CAMELLIA128, 10262306a36Sopenharmony_ci .name = "camellia128-cts-cmac", 10362306a36Sopenharmony_ci .encrypt_name = "cts(cbc(camellia))", 10462306a36Sopenharmony_ci .aux_cipher = "cbc(camellia)", 10562306a36Sopenharmony_ci .cksum_name = "cmac(camellia)", 10662306a36Sopenharmony_ci .cksumlength = BITS2OCTETS(128), 10762306a36Sopenharmony_ci .keyed_cksum = 1, 10862306a36Sopenharmony_ci .keylength = BITS2OCTETS(128), 10962306a36Sopenharmony_ci .Kc_length = BITS2OCTETS(128), 11062306a36Sopenharmony_ci .Ke_length = BITS2OCTETS(128), 11162306a36Sopenharmony_ci .Ki_length = BITS2OCTETS(128), 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci .derive_key = krb5_kdf_feedback_cmac, 11462306a36Sopenharmony_ci .encrypt = gss_krb5_aes_encrypt, 11562306a36Sopenharmony_ci .decrypt = gss_krb5_aes_decrypt, 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci .get_mic = gss_krb5_get_mic_v2, 11862306a36Sopenharmony_ci .verify_mic = gss_krb5_verify_mic_v2, 11962306a36Sopenharmony_ci .wrap = gss_krb5_wrap_v2, 12062306a36Sopenharmony_ci .unwrap = gss_krb5_unwrap_v2, 12162306a36Sopenharmony_ci }, 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * Camellia-256 with CMAC (RFC 6803) 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci { 12662306a36Sopenharmony_ci .etype = ENCTYPE_CAMELLIA256_CTS_CMAC, 12762306a36Sopenharmony_ci .ctype = CKSUMTYPE_CMAC_CAMELLIA256, 12862306a36Sopenharmony_ci .name = "camellia256-cts-cmac", 12962306a36Sopenharmony_ci .encrypt_name = "cts(cbc(camellia))", 13062306a36Sopenharmony_ci .aux_cipher = "cbc(camellia)", 13162306a36Sopenharmony_ci .cksum_name = "cmac(camellia)", 13262306a36Sopenharmony_ci .cksumlength = BITS2OCTETS(128), 13362306a36Sopenharmony_ci .keyed_cksum = 1, 13462306a36Sopenharmony_ci .keylength = BITS2OCTETS(256), 13562306a36Sopenharmony_ci .Kc_length = BITS2OCTETS(256), 13662306a36Sopenharmony_ci .Ke_length = BITS2OCTETS(256), 13762306a36Sopenharmony_ci .Ki_length = BITS2OCTETS(256), 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci .derive_key = krb5_kdf_feedback_cmac, 14062306a36Sopenharmony_ci .encrypt = gss_krb5_aes_encrypt, 14162306a36Sopenharmony_ci .decrypt = gss_krb5_aes_decrypt, 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci .get_mic = gss_krb5_get_mic_v2, 14462306a36Sopenharmony_ci .verify_mic = gss_krb5_verify_mic_v2, 14562306a36Sopenharmony_ci .wrap = gss_krb5_wrap_v2, 14662306a36Sopenharmony_ci .unwrap = gss_krb5_unwrap_v2, 14762306a36Sopenharmony_ci }, 14862306a36Sopenharmony_ci#endif 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2) 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * AES-128 with SHA-256 (RFC 8009) 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci { 15562306a36Sopenharmony_ci .etype = ENCTYPE_AES128_CTS_HMAC_SHA256_128, 15662306a36Sopenharmony_ci .ctype = CKSUMTYPE_HMAC_SHA256_128_AES128, 15762306a36Sopenharmony_ci .name = "aes128-cts-hmac-sha256-128", 15862306a36Sopenharmony_ci .encrypt_name = "cts(cbc(aes))", 15962306a36Sopenharmony_ci .aux_cipher = "cbc(aes)", 16062306a36Sopenharmony_ci .cksum_name = "hmac(sha256)", 16162306a36Sopenharmony_ci .cksumlength = BITS2OCTETS(128), 16262306a36Sopenharmony_ci .keyed_cksum = 1, 16362306a36Sopenharmony_ci .keylength = BITS2OCTETS(128), 16462306a36Sopenharmony_ci .Kc_length = BITS2OCTETS(128), 16562306a36Sopenharmony_ci .Ke_length = BITS2OCTETS(128), 16662306a36Sopenharmony_ci .Ki_length = BITS2OCTETS(128), 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci .derive_key = krb5_kdf_hmac_sha2, 16962306a36Sopenharmony_ci .encrypt = krb5_etm_encrypt, 17062306a36Sopenharmony_ci .decrypt = krb5_etm_decrypt, 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci .get_mic = gss_krb5_get_mic_v2, 17362306a36Sopenharmony_ci .verify_mic = gss_krb5_verify_mic_v2, 17462306a36Sopenharmony_ci .wrap = gss_krb5_wrap_v2, 17562306a36Sopenharmony_ci .unwrap = gss_krb5_unwrap_v2, 17662306a36Sopenharmony_ci }, 17762306a36Sopenharmony_ci /* 17862306a36Sopenharmony_ci * AES-256 with SHA-384 (RFC 8009) 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_ci { 18162306a36Sopenharmony_ci .etype = ENCTYPE_AES256_CTS_HMAC_SHA384_192, 18262306a36Sopenharmony_ci .ctype = CKSUMTYPE_HMAC_SHA384_192_AES256, 18362306a36Sopenharmony_ci .name = "aes256-cts-hmac-sha384-192", 18462306a36Sopenharmony_ci .encrypt_name = "cts(cbc(aes))", 18562306a36Sopenharmony_ci .aux_cipher = "cbc(aes)", 18662306a36Sopenharmony_ci .cksum_name = "hmac(sha384)", 18762306a36Sopenharmony_ci .cksumlength = BITS2OCTETS(192), 18862306a36Sopenharmony_ci .keyed_cksum = 1, 18962306a36Sopenharmony_ci .keylength = BITS2OCTETS(256), 19062306a36Sopenharmony_ci .Kc_length = BITS2OCTETS(192), 19162306a36Sopenharmony_ci .Ke_length = BITS2OCTETS(256), 19262306a36Sopenharmony_ci .Ki_length = BITS2OCTETS(192), 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci .derive_key = krb5_kdf_hmac_sha2, 19562306a36Sopenharmony_ci .encrypt = krb5_etm_encrypt, 19662306a36Sopenharmony_ci .decrypt = krb5_etm_decrypt, 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci .get_mic = gss_krb5_get_mic_v2, 19962306a36Sopenharmony_ci .verify_mic = gss_krb5_verify_mic_v2, 20062306a36Sopenharmony_ci .wrap = gss_krb5_wrap_v2, 20162306a36Sopenharmony_ci .unwrap = gss_krb5_unwrap_v2, 20262306a36Sopenharmony_ci }, 20362306a36Sopenharmony_ci#endif 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* 20762306a36Sopenharmony_ci * The list of advertised enctypes is specified in order of most 20862306a36Sopenharmony_ci * preferred to least. 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_cistatic char gss_krb5_enctype_priority_list[64]; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void gss_krb5_prepare_enctype_priority_list(void) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci static const u32 gss_krb5_enctypes[] = { 21562306a36Sopenharmony_ci#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2) 21662306a36Sopenharmony_ci ENCTYPE_AES256_CTS_HMAC_SHA384_192, 21762306a36Sopenharmony_ci ENCTYPE_AES128_CTS_HMAC_SHA256_128, 21862306a36Sopenharmony_ci#endif 21962306a36Sopenharmony_ci#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA) 22062306a36Sopenharmony_ci ENCTYPE_CAMELLIA256_CTS_CMAC, 22162306a36Sopenharmony_ci ENCTYPE_CAMELLIA128_CTS_CMAC, 22262306a36Sopenharmony_ci#endif 22362306a36Sopenharmony_ci#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1) 22462306a36Sopenharmony_ci ENCTYPE_AES256_CTS_HMAC_SHA1_96, 22562306a36Sopenharmony_ci ENCTYPE_AES128_CTS_HMAC_SHA1_96, 22662306a36Sopenharmony_ci#endif 22762306a36Sopenharmony_ci }; 22862306a36Sopenharmony_ci size_t total, i; 22962306a36Sopenharmony_ci char buf[16]; 23062306a36Sopenharmony_ci char *sep; 23162306a36Sopenharmony_ci int n; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci sep = ""; 23462306a36Sopenharmony_ci gss_krb5_enctype_priority_list[0] = '\0'; 23562306a36Sopenharmony_ci for (total = 0, i = 0; i < ARRAY_SIZE(gss_krb5_enctypes); i++) { 23662306a36Sopenharmony_ci n = sprintf(buf, "%s%u", sep, gss_krb5_enctypes[i]); 23762306a36Sopenharmony_ci if (n < 0) 23862306a36Sopenharmony_ci break; 23962306a36Sopenharmony_ci if (total + n >= sizeof(gss_krb5_enctype_priority_list)) 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci strcat(gss_krb5_enctype_priority_list, buf); 24262306a36Sopenharmony_ci sep = ","; 24362306a36Sopenharmony_ci total += n; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/** 24862306a36Sopenharmony_ci * gss_krb5_lookup_enctype - Retrieve profile information for a given enctype 24962306a36Sopenharmony_ci * @etype: ENCTYPE value 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * Returns a pointer to a gss_krb5_enctype structure, or NULL if no 25262306a36Sopenharmony_ci * matching etype is found. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ciVISIBLE_IF_KUNIT 25562306a36Sopenharmony_ciconst struct gss_krb5_enctype *gss_krb5_lookup_enctype(u32 etype) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci size_t i; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(supported_gss_krb5_enctypes); i++) 26062306a36Sopenharmony_ci if (supported_gss_krb5_enctypes[i].etype == etype) 26162306a36Sopenharmony_ci return &supported_gss_krb5_enctypes[i]; 26262306a36Sopenharmony_ci return NULL; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ciEXPORT_SYMBOL_IF_KUNIT(gss_krb5_lookup_enctype); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic struct crypto_sync_skcipher * 26762306a36Sopenharmony_cigss_krb5_alloc_cipher_v2(const char *cname, const struct xdr_netobj *key) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct crypto_sync_skcipher *tfm; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci tfm = crypto_alloc_sync_skcipher(cname, 0, 0); 27262306a36Sopenharmony_ci if (IS_ERR(tfm)) 27362306a36Sopenharmony_ci return NULL; 27462306a36Sopenharmony_ci if (crypto_sync_skcipher_setkey(tfm, key->data, key->len)) { 27562306a36Sopenharmony_ci crypto_free_sync_skcipher(tfm); 27662306a36Sopenharmony_ci return NULL; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci return tfm; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic struct crypto_ahash * 28262306a36Sopenharmony_cigss_krb5_alloc_hash_v2(struct krb5_ctx *kctx, const struct xdr_netobj *key) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct crypto_ahash *tfm; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); 28762306a36Sopenharmony_ci if (IS_ERR(tfm)) 28862306a36Sopenharmony_ci return NULL; 28962306a36Sopenharmony_ci if (crypto_ahash_setkey(tfm, key->data, key->len)) { 29062306a36Sopenharmony_ci crypto_free_ahash(tfm); 29162306a36Sopenharmony_ci return NULL; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci return tfm; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int 29762306a36Sopenharmony_cigss_krb5_import_ctx_v2(struct krb5_ctx *ctx, gfp_t gfp_mask) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct xdr_netobj keyin = { 30062306a36Sopenharmony_ci .len = ctx->gk5e->keylength, 30162306a36Sopenharmony_ci .data = ctx->Ksess, 30262306a36Sopenharmony_ci }; 30362306a36Sopenharmony_ci struct xdr_netobj keyout; 30462306a36Sopenharmony_ci int ret = -EINVAL; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci keyout.data = kmalloc(GSS_KRB5_MAX_KEYLEN, gfp_mask); 30762306a36Sopenharmony_ci if (!keyout.data) 30862306a36Sopenharmony_ci return -ENOMEM; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* initiator seal encryption */ 31162306a36Sopenharmony_ci keyout.len = ctx->gk5e->Ke_length; 31262306a36Sopenharmony_ci if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_INITIATOR_SEAL, 31362306a36Sopenharmony_ci KEY_USAGE_SEED_ENCRYPTION, gfp_mask)) 31462306a36Sopenharmony_ci goto out; 31562306a36Sopenharmony_ci ctx->initiator_enc = gss_krb5_alloc_cipher_v2(ctx->gk5e->encrypt_name, 31662306a36Sopenharmony_ci &keyout); 31762306a36Sopenharmony_ci if (ctx->initiator_enc == NULL) 31862306a36Sopenharmony_ci goto out; 31962306a36Sopenharmony_ci if (ctx->gk5e->aux_cipher) { 32062306a36Sopenharmony_ci ctx->initiator_enc_aux = 32162306a36Sopenharmony_ci gss_krb5_alloc_cipher_v2(ctx->gk5e->aux_cipher, 32262306a36Sopenharmony_ci &keyout); 32362306a36Sopenharmony_ci if (ctx->initiator_enc_aux == NULL) 32462306a36Sopenharmony_ci goto out_free; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* acceptor seal encryption */ 32862306a36Sopenharmony_ci if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_ACCEPTOR_SEAL, 32962306a36Sopenharmony_ci KEY_USAGE_SEED_ENCRYPTION, gfp_mask)) 33062306a36Sopenharmony_ci goto out_free; 33162306a36Sopenharmony_ci ctx->acceptor_enc = gss_krb5_alloc_cipher_v2(ctx->gk5e->encrypt_name, 33262306a36Sopenharmony_ci &keyout); 33362306a36Sopenharmony_ci if (ctx->acceptor_enc == NULL) 33462306a36Sopenharmony_ci goto out_free; 33562306a36Sopenharmony_ci if (ctx->gk5e->aux_cipher) { 33662306a36Sopenharmony_ci ctx->acceptor_enc_aux = 33762306a36Sopenharmony_ci gss_krb5_alloc_cipher_v2(ctx->gk5e->aux_cipher, 33862306a36Sopenharmony_ci &keyout); 33962306a36Sopenharmony_ci if (ctx->acceptor_enc_aux == NULL) 34062306a36Sopenharmony_ci goto out_free; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* initiator sign checksum */ 34462306a36Sopenharmony_ci keyout.len = ctx->gk5e->Kc_length; 34562306a36Sopenharmony_ci if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_INITIATOR_SIGN, 34662306a36Sopenharmony_ci KEY_USAGE_SEED_CHECKSUM, gfp_mask)) 34762306a36Sopenharmony_ci goto out_free; 34862306a36Sopenharmony_ci ctx->initiator_sign = gss_krb5_alloc_hash_v2(ctx, &keyout); 34962306a36Sopenharmony_ci if (ctx->initiator_sign == NULL) 35062306a36Sopenharmony_ci goto out_free; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* acceptor sign checksum */ 35362306a36Sopenharmony_ci if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_ACCEPTOR_SIGN, 35462306a36Sopenharmony_ci KEY_USAGE_SEED_CHECKSUM, gfp_mask)) 35562306a36Sopenharmony_ci goto out_free; 35662306a36Sopenharmony_ci ctx->acceptor_sign = gss_krb5_alloc_hash_v2(ctx, &keyout); 35762306a36Sopenharmony_ci if (ctx->acceptor_sign == NULL) 35862306a36Sopenharmony_ci goto out_free; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* initiator seal integrity */ 36162306a36Sopenharmony_ci keyout.len = ctx->gk5e->Ki_length; 36262306a36Sopenharmony_ci if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_INITIATOR_SEAL, 36362306a36Sopenharmony_ci KEY_USAGE_SEED_INTEGRITY, gfp_mask)) 36462306a36Sopenharmony_ci goto out_free; 36562306a36Sopenharmony_ci ctx->initiator_integ = gss_krb5_alloc_hash_v2(ctx, &keyout); 36662306a36Sopenharmony_ci if (ctx->initiator_integ == NULL) 36762306a36Sopenharmony_ci goto out_free; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* acceptor seal integrity */ 37062306a36Sopenharmony_ci if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_ACCEPTOR_SEAL, 37162306a36Sopenharmony_ci KEY_USAGE_SEED_INTEGRITY, gfp_mask)) 37262306a36Sopenharmony_ci goto out_free; 37362306a36Sopenharmony_ci ctx->acceptor_integ = gss_krb5_alloc_hash_v2(ctx, &keyout); 37462306a36Sopenharmony_ci if (ctx->acceptor_integ == NULL) 37562306a36Sopenharmony_ci goto out_free; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci ret = 0; 37862306a36Sopenharmony_ciout: 37962306a36Sopenharmony_ci kfree_sensitive(keyout.data); 38062306a36Sopenharmony_ci return ret; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ciout_free: 38362306a36Sopenharmony_ci crypto_free_ahash(ctx->acceptor_integ); 38462306a36Sopenharmony_ci crypto_free_ahash(ctx->initiator_integ); 38562306a36Sopenharmony_ci crypto_free_ahash(ctx->acceptor_sign); 38662306a36Sopenharmony_ci crypto_free_ahash(ctx->initiator_sign); 38762306a36Sopenharmony_ci crypto_free_sync_skcipher(ctx->acceptor_enc_aux); 38862306a36Sopenharmony_ci crypto_free_sync_skcipher(ctx->acceptor_enc); 38962306a36Sopenharmony_ci crypto_free_sync_skcipher(ctx->initiator_enc_aux); 39062306a36Sopenharmony_ci crypto_free_sync_skcipher(ctx->initiator_enc); 39162306a36Sopenharmony_ci goto out; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int 39562306a36Sopenharmony_cigss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx, 39662306a36Sopenharmony_ci gfp_t gfp_mask) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci u64 seq_send64; 39962306a36Sopenharmony_ci int keylen; 40062306a36Sopenharmony_ci u32 time32; 40162306a36Sopenharmony_ci int ret; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags)); 40462306a36Sopenharmony_ci if (IS_ERR(p)) 40562306a36Sopenharmony_ci goto out_err; 40662306a36Sopenharmony_ci ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci p = simple_get_bytes(p, end, &time32, sizeof(time32)); 40962306a36Sopenharmony_ci if (IS_ERR(p)) 41062306a36Sopenharmony_ci goto out_err; 41162306a36Sopenharmony_ci /* unsigned 32-bit time overflows in year 2106 */ 41262306a36Sopenharmony_ci ctx->endtime = (time64_t)time32; 41362306a36Sopenharmony_ci p = simple_get_bytes(p, end, &seq_send64, sizeof(seq_send64)); 41462306a36Sopenharmony_ci if (IS_ERR(p)) 41562306a36Sopenharmony_ci goto out_err; 41662306a36Sopenharmony_ci atomic64_set(&ctx->seq_send64, seq_send64); 41762306a36Sopenharmony_ci /* set seq_send for use by "older" enctypes */ 41862306a36Sopenharmony_ci atomic_set(&ctx->seq_send, seq_send64); 41962306a36Sopenharmony_ci if (seq_send64 != atomic_read(&ctx->seq_send)) { 42062306a36Sopenharmony_ci dprintk("%s: seq_send64 %llx, seq_send %x overflow?\n", __func__, 42162306a36Sopenharmony_ci seq_send64, atomic_read(&ctx->seq_send)); 42262306a36Sopenharmony_ci p = ERR_PTR(-EINVAL); 42362306a36Sopenharmony_ci goto out_err; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype)); 42662306a36Sopenharmony_ci if (IS_ERR(p)) 42762306a36Sopenharmony_ci goto out_err; 42862306a36Sopenharmony_ci ctx->gk5e = gss_krb5_lookup_enctype(ctx->enctype); 42962306a36Sopenharmony_ci if (ctx->gk5e == NULL) { 43062306a36Sopenharmony_ci dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n", 43162306a36Sopenharmony_ci ctx->enctype); 43262306a36Sopenharmony_ci p = ERR_PTR(-EINVAL); 43362306a36Sopenharmony_ci goto out_err; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci keylen = ctx->gk5e->keylength; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci p = simple_get_bytes(p, end, ctx->Ksess, keylen); 43862306a36Sopenharmony_ci if (IS_ERR(p)) 43962306a36Sopenharmony_ci goto out_err; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (p != end) { 44262306a36Sopenharmony_ci p = ERR_PTR(-EINVAL); 44362306a36Sopenharmony_ci goto out_err; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data, 44762306a36Sopenharmony_ci gss_kerberos_mech.gm_oid.len, gfp_mask); 44862306a36Sopenharmony_ci if (unlikely(ctx->mech_used.data == NULL)) { 44962306a36Sopenharmony_ci p = ERR_PTR(-ENOMEM); 45062306a36Sopenharmony_ci goto out_err; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci ctx->mech_used.len = gss_kerberos_mech.gm_oid.len; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci ret = gss_krb5_import_ctx_v2(ctx, gfp_mask); 45562306a36Sopenharmony_ci if (ret) { 45662306a36Sopenharmony_ci p = ERR_PTR(ret); 45762306a36Sopenharmony_ci goto out_free; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ciout_free: 46362306a36Sopenharmony_ci kfree(ctx->mech_used.data); 46462306a36Sopenharmony_ciout_err: 46562306a36Sopenharmony_ci return PTR_ERR(p); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int 46962306a36Sopenharmony_cigss_krb5_import_sec_context(const void *p, size_t len, struct gss_ctx *ctx_id, 47062306a36Sopenharmony_ci time64_t *endtime, gfp_t gfp_mask) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci const void *end = (const void *)((const char *)p + len); 47362306a36Sopenharmony_ci struct krb5_ctx *ctx; 47462306a36Sopenharmony_ci int ret; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), gfp_mask); 47762306a36Sopenharmony_ci if (ctx == NULL) 47862306a36Sopenharmony_ci return -ENOMEM; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci ret = gss_import_v2_context(p, end, ctx, gfp_mask); 48162306a36Sopenharmony_ci memzero_explicit(&ctx->Ksess, sizeof(ctx->Ksess)); 48262306a36Sopenharmony_ci if (ret) { 48362306a36Sopenharmony_ci kfree(ctx); 48462306a36Sopenharmony_ci return ret; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci ctx_id->internal_ctx_id = ctx; 48862306a36Sopenharmony_ci if (endtime) 48962306a36Sopenharmony_ci *endtime = ctx->endtime; 49062306a36Sopenharmony_ci return 0; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic void 49462306a36Sopenharmony_cigss_krb5_delete_sec_context(void *internal_ctx) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct krb5_ctx *kctx = internal_ctx; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci crypto_free_sync_skcipher(kctx->seq); 49962306a36Sopenharmony_ci crypto_free_sync_skcipher(kctx->enc); 50062306a36Sopenharmony_ci crypto_free_sync_skcipher(kctx->acceptor_enc); 50162306a36Sopenharmony_ci crypto_free_sync_skcipher(kctx->initiator_enc); 50262306a36Sopenharmony_ci crypto_free_sync_skcipher(kctx->acceptor_enc_aux); 50362306a36Sopenharmony_ci crypto_free_sync_skcipher(kctx->initiator_enc_aux); 50462306a36Sopenharmony_ci crypto_free_ahash(kctx->acceptor_sign); 50562306a36Sopenharmony_ci crypto_free_ahash(kctx->initiator_sign); 50662306a36Sopenharmony_ci crypto_free_ahash(kctx->acceptor_integ); 50762306a36Sopenharmony_ci crypto_free_ahash(kctx->initiator_integ); 50862306a36Sopenharmony_ci kfree(kctx->mech_used.data); 50962306a36Sopenharmony_ci kfree(kctx); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci/** 51362306a36Sopenharmony_ci * gss_krb5_get_mic - get_mic for the Kerberos GSS mechanism 51462306a36Sopenharmony_ci * @gctx: GSS context 51562306a36Sopenharmony_ci * @text: plaintext to checksum 51662306a36Sopenharmony_ci * @token: buffer into which to write the computed checksum 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci * Return values: 51962306a36Sopenharmony_ci * %GSS_S_COMPLETE - success, and @token is filled in 52062306a36Sopenharmony_ci * %GSS_S_FAILURE - checksum could not be generated 52162306a36Sopenharmony_ci * %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_cistatic u32 gss_krb5_get_mic(struct gss_ctx *gctx, struct xdr_buf *text, 52462306a36Sopenharmony_ci struct xdr_netobj *token) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct krb5_ctx *kctx = gctx->internal_ctx_id; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return kctx->gk5e->get_mic(kctx, text, token); 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci/** 53262306a36Sopenharmony_ci * gss_krb5_verify_mic - verify_mic for the Kerberos GSS mechanism 53362306a36Sopenharmony_ci * @gctx: GSS context 53462306a36Sopenharmony_ci * @message_buffer: plaintext to check 53562306a36Sopenharmony_ci * @read_token: received checksum to check 53662306a36Sopenharmony_ci * 53762306a36Sopenharmony_ci * Return values: 53862306a36Sopenharmony_ci * %GSS_S_COMPLETE - computed and received checksums match 53962306a36Sopenharmony_ci * %GSS_S_DEFECTIVE_TOKEN - received checksum is not valid 54062306a36Sopenharmony_ci * %GSS_S_BAD_SIG - computed and received checksums do not match 54162306a36Sopenharmony_ci * %GSS_S_FAILURE - received checksum could not be checked 54262306a36Sopenharmony_ci * %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_cistatic u32 gss_krb5_verify_mic(struct gss_ctx *gctx, 54562306a36Sopenharmony_ci struct xdr_buf *message_buffer, 54662306a36Sopenharmony_ci struct xdr_netobj *read_token) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct krb5_ctx *kctx = gctx->internal_ctx_id; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return kctx->gk5e->verify_mic(kctx, message_buffer, read_token); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/** 55462306a36Sopenharmony_ci * gss_krb5_wrap - gss_wrap for the Kerberos GSS mechanism 55562306a36Sopenharmony_ci * @gctx: initialized GSS context 55662306a36Sopenharmony_ci * @offset: byte offset in @buf to start writing the cipher text 55762306a36Sopenharmony_ci * @buf: OUT: send buffer 55862306a36Sopenharmony_ci * @pages: plaintext to wrap 55962306a36Sopenharmony_ci * 56062306a36Sopenharmony_ci * Return values: 56162306a36Sopenharmony_ci * %GSS_S_COMPLETE - success, @buf has been updated 56262306a36Sopenharmony_ci * %GSS_S_FAILURE - @buf could not be wrapped 56362306a36Sopenharmony_ci * %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_cistatic u32 gss_krb5_wrap(struct gss_ctx *gctx, int offset, 56662306a36Sopenharmony_ci struct xdr_buf *buf, struct page **pages) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct krb5_ctx *kctx = gctx->internal_ctx_id; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci return kctx->gk5e->wrap(kctx, offset, buf, pages); 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/** 57462306a36Sopenharmony_ci * gss_krb5_unwrap - gss_unwrap for the Kerberos GSS mechanism 57562306a36Sopenharmony_ci * @gctx: initialized GSS context 57662306a36Sopenharmony_ci * @offset: starting byte offset into @buf 57762306a36Sopenharmony_ci * @len: size of ciphertext to unwrap 57862306a36Sopenharmony_ci * @buf: ciphertext to unwrap 57962306a36Sopenharmony_ci * 58062306a36Sopenharmony_ci * Return values: 58162306a36Sopenharmony_ci * %GSS_S_COMPLETE - success, @buf has been updated 58262306a36Sopenharmony_ci * %GSS_S_DEFECTIVE_TOKEN - received blob is not valid 58362306a36Sopenharmony_ci * %GSS_S_BAD_SIG - computed and received checksums do not match 58462306a36Sopenharmony_ci * %GSS_S_FAILURE - @buf could not be unwrapped 58562306a36Sopenharmony_ci * %GSS_S_CONTEXT_EXPIRED - Kerberos context is no longer valid 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_cistatic u32 gss_krb5_unwrap(struct gss_ctx *gctx, int offset, 58862306a36Sopenharmony_ci int len, struct xdr_buf *buf) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct krb5_ctx *kctx = gctx->internal_ctx_id; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return kctx->gk5e->unwrap(kctx, offset, len, buf, 59362306a36Sopenharmony_ci &gctx->slack, &gctx->align); 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_cistatic const struct gss_api_ops gss_kerberos_ops = { 59762306a36Sopenharmony_ci .gss_import_sec_context = gss_krb5_import_sec_context, 59862306a36Sopenharmony_ci .gss_get_mic = gss_krb5_get_mic, 59962306a36Sopenharmony_ci .gss_verify_mic = gss_krb5_verify_mic, 60062306a36Sopenharmony_ci .gss_wrap = gss_krb5_wrap, 60162306a36Sopenharmony_ci .gss_unwrap = gss_krb5_unwrap, 60262306a36Sopenharmony_ci .gss_delete_sec_context = gss_krb5_delete_sec_context, 60362306a36Sopenharmony_ci}; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic struct pf_desc gss_kerberos_pfs[] = { 60662306a36Sopenharmony_ci [0] = { 60762306a36Sopenharmony_ci .pseudoflavor = RPC_AUTH_GSS_KRB5, 60862306a36Sopenharmony_ci .qop = GSS_C_QOP_DEFAULT, 60962306a36Sopenharmony_ci .service = RPC_GSS_SVC_NONE, 61062306a36Sopenharmony_ci .name = "krb5", 61162306a36Sopenharmony_ci }, 61262306a36Sopenharmony_ci [1] = { 61362306a36Sopenharmony_ci .pseudoflavor = RPC_AUTH_GSS_KRB5I, 61462306a36Sopenharmony_ci .qop = GSS_C_QOP_DEFAULT, 61562306a36Sopenharmony_ci .service = RPC_GSS_SVC_INTEGRITY, 61662306a36Sopenharmony_ci .name = "krb5i", 61762306a36Sopenharmony_ci .datatouch = true, 61862306a36Sopenharmony_ci }, 61962306a36Sopenharmony_ci [2] = { 62062306a36Sopenharmony_ci .pseudoflavor = RPC_AUTH_GSS_KRB5P, 62162306a36Sopenharmony_ci .qop = GSS_C_QOP_DEFAULT, 62262306a36Sopenharmony_ci .service = RPC_GSS_SVC_PRIVACY, 62362306a36Sopenharmony_ci .name = "krb5p", 62462306a36Sopenharmony_ci .datatouch = true, 62562306a36Sopenharmony_ci }, 62662306a36Sopenharmony_ci}; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ciMODULE_ALIAS("rpc-auth-gss-krb5"); 62962306a36Sopenharmony_ciMODULE_ALIAS("rpc-auth-gss-krb5i"); 63062306a36Sopenharmony_ciMODULE_ALIAS("rpc-auth-gss-krb5p"); 63162306a36Sopenharmony_ciMODULE_ALIAS("rpc-auth-gss-390003"); 63262306a36Sopenharmony_ciMODULE_ALIAS("rpc-auth-gss-390004"); 63362306a36Sopenharmony_ciMODULE_ALIAS("rpc-auth-gss-390005"); 63462306a36Sopenharmony_ciMODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2"); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic struct gss_api_mech gss_kerberos_mech = { 63762306a36Sopenharmony_ci .gm_name = "krb5", 63862306a36Sopenharmony_ci .gm_owner = THIS_MODULE, 63962306a36Sopenharmony_ci .gm_oid = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }, 64062306a36Sopenharmony_ci .gm_ops = &gss_kerberos_ops, 64162306a36Sopenharmony_ci .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), 64262306a36Sopenharmony_ci .gm_pfs = gss_kerberos_pfs, 64362306a36Sopenharmony_ci .gm_upcall_enctypes = gss_krb5_enctype_priority_list, 64462306a36Sopenharmony_ci}; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int __init init_kerberos_module(void) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci int status; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci gss_krb5_prepare_enctype_priority_list(); 65162306a36Sopenharmony_ci status = gss_mech_register(&gss_kerberos_mech); 65262306a36Sopenharmony_ci if (status) 65362306a36Sopenharmony_ci printk("Failed to register kerberos gss mechanism!\n"); 65462306a36Sopenharmony_ci return status; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic void __exit cleanup_kerberos_module(void) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci gss_mech_unregister(&gss_kerberos_mech); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 66362306a36Sopenharmony_cimodule_init(init_kerberos_module); 66462306a36Sopenharmony_cimodule_exit(cleanup_kerberos_module); 665