summaryrefslogtreecommitdiff
path: root/net/sunrpc/auth_gss/gss_krb5_keys.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/auth_gss/gss_krb5_keys.c')
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_keys.c131
1 files changed, 86 insertions, 45 deletions
diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c
index a7c6866dad96..f6de4fdd63ae 100644
--- a/net/sunrpc/auth_gss/gss_krb5_keys.c
+++ b/net/sunrpc/auth_gss/gss_krb5_keys.c
@@ -139,23 +139,20 @@ static void krb5_nfold(u32 inbits, const u8 *in,
* This is the DK (derive_key) function as described in rfc3961, sec 5.1
* Taken from MIT Kerberos and modified.
*/
-
-u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e,
- const struct xdr_netobj *inkey,
- struct xdr_netobj *outkey,
- const struct xdr_netobj *in_constant,
- gfp_t gfp_mask)
+static int krb5_DK(const struct gss_krb5_enctype *gk5e,
+ const struct xdr_netobj *inkey, u8 *rawkey,
+ const struct xdr_netobj *in_constant, gfp_t gfp_mask)
{
size_t blocksize, keybytes, keylength, n;
- unsigned char *inblockdata, *outblockdata, *rawkey;
+ unsigned char *inblockdata, *outblockdata;
struct xdr_netobj inblock, outblock;
struct crypto_sync_skcipher *cipher;
- u32 ret = EINVAL;
+ int ret = -EINVAL;
keybytes = gk5e->keybytes;
keylength = gk5e->keylength;
- if ((inkey->len != keylength) || (outkey->len != keylength))
+ if (inkey->len != keylength)
goto err_return;
cipher = crypto_alloc_sync_skcipher(gk5e->encrypt_name, 0, 0);
@@ -165,7 +162,7 @@ u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e,
if (crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len))
goto err_return;
- ret = ENOMEM;
+ ret = -ENOMEM;
inblockdata = kmalloc(blocksize, gfp_mask);
if (inblockdata == NULL)
goto err_free_cipher;
@@ -174,10 +171,6 @@ u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e,
if (outblockdata == NULL)
goto err_free_in;
- rawkey = kmalloc(keybytes, gfp_mask);
- if (rawkey == NULL)
- goto err_free_out;
-
inblock.data = (char *) inblockdata;
inblock.len = blocksize;
@@ -210,26 +203,8 @@ u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e,
n += outblock.len;
}
- /* postprocess the key */
-
- inblock.data = (char *) rawkey;
- inblock.len = keybytes;
-
- BUG_ON(gk5e->mk_key == NULL);
- ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey);
- if (ret) {
- dprintk("%s: got %d from mk_key function for '%s'\n",
- __func__, ret, gk5e->encrypt_name);
- goto err_free_raw;
- }
-
- /* clean memory, free resources and exit */
-
ret = 0;
-err_free_raw:
- kfree_sensitive(rawkey);
-err_free_out:
kfree_sensitive(outblockdata);
err_free_in:
kfree_sensitive(inblockdata);
@@ -252,15 +227,11 @@ static void mit_des_fixup_key_parity(u8 key[8])
}
}
-/*
- * This is the des3 key derivation postprocess function
- */
-u32 gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e,
- struct xdr_netobj *randombits,
- struct xdr_netobj *key)
+static int krb5_random_to_key_v1(const struct gss_krb5_enctype *gk5e,
+ struct xdr_netobj *randombits,
+ struct xdr_netobj *key)
{
- int i;
- u32 ret = EINVAL;
+ int i, ret = -EINVAL;
if (key->len != 24) {
dprintk("%s: key->len is %d\n", __func__, key->len);
@@ -292,14 +263,49 @@ err_out:
return ret;
}
+/**
+ * krb5_derive_key_v1 - Derive a subkey for an RFC 3961 enctype
+ * @gk5e: Kerberos 5 enctype profile
+ * @inkey: base protocol key
+ * @outkey: OUT: derived key
+ * @label: subkey usage label
+ * @gfp_mask: memory allocation control flags
+ *
+ * Caller sets @outkey->len to the desired length of the derived key.
+ *
+ * On success, returns 0 and fills in @outkey. A negative errno value
+ * is returned on failure.
+ */
+int krb5_derive_key_v1(const struct gss_krb5_enctype *gk5e,
+ const struct xdr_netobj *inkey,
+ struct xdr_netobj *outkey,
+ const struct xdr_netobj *label,
+ gfp_t gfp_mask)
+{
+ struct xdr_netobj inblock;
+ int ret;
+
+ inblock.len = gk5e->keybytes;
+ inblock.data = kmalloc(inblock.len, gfp_mask);
+ if (!inblock.data)
+ return -ENOMEM;
+
+ ret = krb5_DK(gk5e, inkey, inblock.data, label, gfp_mask);
+ if (!ret)
+ ret = krb5_random_to_key_v1(gk5e, &inblock, outkey);
+
+ kfree_sensitive(inblock.data);
+ return ret;
+}
+
/*
- * This is the aes key derivation postprocess function
+ * This is the identity function, with some sanity checking.
*/
-u32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e,
- struct xdr_netobj *randombits,
- struct xdr_netobj *key)
+static int krb5_random_to_key_v2(const struct gss_krb5_enctype *gk5e,
+ struct xdr_netobj *randombits,
+ struct xdr_netobj *key)
{
- u32 ret = EINVAL;
+ int ret = -EINVAL;
if (key->len != 16 && key->len != 32) {
dprintk("%s: key->len is %d\n", __func__, key->len);
@@ -320,3 +326,38 @@ u32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e,
err_out:
return ret;
}
+
+/**
+ * krb5_derive_key_v2 - Derive a subkey for an RFC 3962 enctype
+ * @gk5e: Kerberos 5 enctype profile
+ * @inkey: base protocol key
+ * @outkey: OUT: derived key
+ * @label: subkey usage label
+ * @gfp_mask: memory allocation control flags
+ *
+ * Caller sets @outkey->len to the desired length of the derived key.
+ *
+ * On success, returns 0 and fills in @outkey. A negative errno value
+ * is returned on failure.
+ */
+int krb5_derive_key_v2(const struct gss_krb5_enctype *gk5e,
+ const struct xdr_netobj *inkey,
+ struct xdr_netobj *outkey,
+ const struct xdr_netobj *label,
+ gfp_t gfp_mask)
+{
+ struct xdr_netobj inblock;
+ int ret;
+
+ inblock.len = gk5e->keybytes;
+ inblock.data = kmalloc(inblock.len, gfp_mask);
+ if (!inblock.data)
+ return -ENOMEM;
+
+ ret = krb5_DK(gk5e, inkey, inblock.data, label, gfp_mask);
+ if (!ret)
+ ret = krb5_random_to_key_v2(gk5e, &inblock, outkey);
+
+ kfree_sensitive(inblock.data);
+ return ret;
+}