@@ -136,3 +136,23 @@ int krb5_derive_Ki(const struct krb5_enctype *krb5, const struct krb5_buffer *TK
* rfc3961_simplified.c
*/
extern const struct krb5_crypto_profile rfc3961_simplified_profile;
+
+int krb5enc_derive_encrypt_keys(const struct krb5_enctype *krb5,
+ const struct krb5_buffer *TK,
+ unsigned int usage,
+ struct krb5_buffer *setkey,
+ gfp_t gfp);
+int krb5enc_load_encrypt_keys(const struct krb5_enctype *krb5,
+ const struct krb5_buffer *Ke,
+ const struct krb5_buffer *Ki,
+ struct krb5_buffer *setkey,
+ gfp_t gfp);
+int rfc3961_derive_checksum_key(const struct krb5_enctype *krb5,
+ const struct krb5_buffer *TK,
+ unsigned int usage,
+ struct krb5_buffer *setkey,
+ gfp_t gfp);
+int rfc3961_load_checksum_key(const struct krb5_enctype *krb5,
+ const struct krb5_buffer *Kc,
+ struct krb5_buffer *setkey,
+ gfp_t gfp);
@@ -399,9 +399,117 @@ static int rfc3961_calc_PRF(const struct krb5_enctype *krb5,
return ret;
}
+/*
+ * Derive the Ke and Ki keys and package them into a key parameter that can be
+ * given to the setkey of a krb5enc AEAD crypto object.
+ */
+int krb5enc_derive_encrypt_keys(const struct krb5_enctype *krb5,
+ const struct krb5_buffer *TK,
+ unsigned int usage,
+ struct krb5_buffer *setkey,
+ gfp_t gfp)
+{
+ struct krb5_buffer Ke, Ki;
+ __be32 *khdr = NULL;
+ int ret;
+
+ Ke.len = krb5->Ke_len;
+ Ki.len = krb5->Ki_len;
+ setkey->len = sizeof(__be32) * 3 + krb5->Ke_len + krb5->Ki_len;
+ setkey->data = kzalloc(setkey->len, GFP_KERNEL);
+ if (!setkey->data)
+ return -ENOMEM;
+
+ khdr = setkey->data;
+ Ke.data = setkey->data + 12;
+ Ki.data = setkey->data + 12 + Ke.len;
+
+ khdr[0] = htonl(1); /* Format 1 */
+ khdr[1] = htonl(Ke.len);
+ khdr[2] = htonl(Ki.len);
+
+ ret = krb5_derive_Ke(krb5, TK, usage, &Ke, gfp);
+ if (ret < 0) {
+ pr_err("get_Ke failed %d\n", ret);
+ return ret;
+ }
+ ret = krb5_derive_Ki(krb5, TK, usage, &Ki, gfp);
+ if (ret < 0)
+ pr_err("get_Ki failed %d\n", ret);
+ return ret;
+}
+
+/*
+ * Package predefined Ke and Ki keys and into a key parameter that can be given
+ * to the setkey of a krb5enc AEAD crypto object.
+ */
+int krb5enc_load_encrypt_keys(const struct krb5_enctype *krb5,
+ const struct krb5_buffer *Ke,
+ const struct krb5_buffer *Ki,
+ struct krb5_buffer *setkey,
+ gfp_t gfp)
+{
+ __be32 *khdr = NULL;
+
+ setkey->len = sizeof(__be32) * 3 + Ke->len + Ki->len;
+ setkey->data = kzalloc(setkey->len, GFP_KERNEL);
+ if (!setkey->data)
+ return -ENOMEM;
+
+ khdr = setkey->data;
+ khdr[0] = htonl(1); /* Format 1 */
+ khdr[1] = htonl(Ke->len);
+ khdr[2] = htonl(Ki->len);
+ memcpy(setkey->data + 12, Ke->data, Ke->len);
+ memcpy(setkey->data + 12 + Ke->len, Ki->data, Ki->len);
+ return 0;
+}
+
+/*
+ * Derive the Kc key for checksum-only mode and package it into a key parameter
+ * that can be given to the setkey of a hash crypto object.
+ */
+int rfc3961_derive_checksum_key(const struct krb5_enctype *krb5,
+ const struct krb5_buffer *TK,
+ unsigned int usage,
+ struct krb5_buffer *setkey,
+ gfp_t gfp)
+{
+ int ret;
+
+ setkey->len = krb5->Kc_len;
+ setkey->data = kzalloc(setkey->len, GFP_KERNEL);
+ if (!setkey->data)
+ return -ENOMEM;
+
+ ret = krb5_derive_Kc(krb5, TK, usage, setkey, gfp);
+ if (ret < 0)
+ pr_err("get_Kc failed %d\n", ret);
+ return ret;
+}
+
+/*
+ * Package a predefined Kc key for checksum-only mode into a key parameter that
+ * can be given to the setkey of a hash crypto object.
+ */
+int rfc3961_load_checksum_key(const struct krb5_enctype *krb5,
+ const struct krb5_buffer *Kc,
+ struct krb5_buffer *setkey,
+ gfp_t gfp)
+{
+ setkey->len = krb5->Kc_len;
+ setkey->data = kmemdup(Kc->data, Kc->len, GFP_KERNEL);
+ if (!setkey->data)
+ return -ENOMEM;
+ return 0;
+}
const struct krb5_crypto_profile rfc3961_simplified_profile = {
- .calc_PRF = rfc3961_calc_PRF,
- .calc_Kc = rfc3961_calc_DK,
- .calc_Ke = rfc3961_calc_DK,
- .calc_Ki = rfc3961_calc_DK,
+ .calc_PRF = rfc3961_calc_PRF,
+ .calc_Kc = rfc3961_calc_DK,
+ .calc_Ke = rfc3961_calc_DK,
+ .calc_Ki = rfc3961_calc_DK,
+ .derive_encrypt_keys = krb5enc_derive_encrypt_keys,
+ .load_encrypt_keys = krb5enc_load_encrypt_keys,
+ .derive_checksum_key = rfc3961_derive_checksum_key,
+ .load_checksum_key = rfc3961_load_checksum_key,
};
Provide functions to derive keys according to RFC3961 (or load the derived keys for the selftester where only derived keys are available) and to package them up appropriately for passing to a krb5enc AEAD setkey or a hash setkey function. Signed-off-by: David Howells <dhowells@redhat.com> cc: Herbert Xu <herbert@gondor.apana.org.au> cc: "David S. Miller" <davem@davemloft.net> cc: Chuck Lever <chuck.lever@oracle.com> cc: Marc Dionne <marc.dionne@auristor.com> cc: Eric Dumazet <edumazet@google.com> cc: Jakub Kicinski <kuba@kernel.org> cc: Paolo Abeni <pabeni@redhat.com> cc: Simon Horman <horms@kernel.org> cc: linux-afs@lists.infradead.org cc: linux-nfs@vger.kernel.org cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org --- crypto/krb5/internal.h | 20 ++++++ crypto/krb5/rfc3961_simplified.c | 116 +++++++++++++++++++++++++++++-- 2 files changed, 132 insertions(+), 4 deletions(-)