rxgk_kdf.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /* RxGK transport key derivation.
  3. *
  4. * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
  5. * Written by David Howells (dhowells@redhat.com)
  6. */
  7. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  8. #include <linux/key-type.h>
  9. #include <linux/slab.h>
  10. #include <keys/rxrpc-type.h>
  11. #include "ar-internal.h"
  12. #include "rxgk_common.h"
  13. #define round16(x) (((x) + 15) & ~15)
  14. /*
  15. * Constants used to derive the keys and hmacs actually used for doing stuff.
  16. */
  17. #define RXGK_CLIENT_ENC_PACKET 1026U // 0x402
  18. #define RXGK_CLIENT_MIC_PACKET 1027U // 0x403
  19. #define RXGK_SERVER_ENC_PACKET 1028U // 0x404
  20. #define RXGK_SERVER_MIC_PACKET 1029U // 0x405
  21. #define RXGK_CLIENT_ENC_RESPONSE 1030U // 0x406
  22. #define RXGK_SERVER_ENC_TOKEN 1036U // 0x40c
  23. static void rxgk_free(struct rxgk_context *gk)
  24. {
  25. if (gk->tx_Kc)
  26. crypto_free_shash(gk->tx_Kc);
  27. if (gk->rx_Kc)
  28. crypto_free_shash(gk->rx_Kc);
  29. if (gk->tx_enc)
  30. crypto_free_aead(gk->tx_enc);
  31. if (gk->rx_enc)
  32. crypto_free_aead(gk->rx_enc);
  33. if (gk->resp_enc)
  34. crypto_free_aead(gk->resp_enc);
  35. kfree(gk);
  36. }
  37. void rxgk_put(struct rxgk_context *gk)
  38. {
  39. if (gk && refcount_dec_and_test(&gk->usage))
  40. rxgk_free(gk);
  41. }
  42. /*
  43. * Transport key derivation function.
  44. *
  45. * TK = random-to-key(PRF+(K0, L,
  46. * epoch || cid || start_time || key_number))
  47. * [tools.ietf.org/html/draft-wilkinson-afs3-rxgk-11 sec 8.3]
  48. */
  49. static int rxgk_derive_transport_key(struct rxrpc_connection *conn,
  50. struct rxgk_context *gk,
  51. const struct rxgk_key *rxgk,
  52. struct krb5_buffer *TK,
  53. gfp_t gfp)
  54. {
  55. const struct krb5_enctype *krb5 = gk->krb5;
  56. struct krb5_buffer conn_info;
  57. unsigned int L = krb5->key_bytes;
  58. __be32 *info;
  59. u8 *buffer;
  60. int ret;
  61. _enter("");
  62. conn_info.len = sizeof(__be32) * 5;
  63. buffer = kzalloc(round16(conn_info.len), gfp);
  64. if (!buffer)
  65. return -ENOMEM;
  66. conn_info.data = buffer;
  67. info = (__be32 *)conn_info.data;
  68. info[0] = htonl(conn->proto.epoch);
  69. info[1] = htonl(conn->proto.cid);
  70. info[2] = htonl(conn->rxgk.start_time >> 32);
  71. info[3] = htonl(conn->rxgk.start_time >> 0);
  72. info[4] = htonl(gk->key_number);
  73. ret = crypto_krb5_calc_PRFplus(krb5, &rxgk->key, L, &conn_info, TK, gfp);
  74. kfree_sensitive(buffer);
  75. _leave(" = %d", ret);
  76. return ret;
  77. }
  78. /*
  79. * Set up the ciphers for the usage keys.
  80. */
  81. static int rxgk_set_up_ciphers(struct rxrpc_connection *conn,
  82. struct rxgk_context *gk,
  83. const struct rxgk_key *rxgk,
  84. gfp_t gfp)
  85. {
  86. const struct krb5_enctype *krb5 = gk->krb5;
  87. struct crypto_shash *shash;
  88. struct crypto_aead *aead;
  89. struct krb5_buffer TK;
  90. bool service = rxrpc_conn_is_service(conn);
  91. int ret;
  92. u8 *buffer;
  93. buffer = kzalloc(krb5->key_bytes, gfp);
  94. if (!buffer)
  95. return -ENOMEM;
  96. TK.len = krb5->key_bytes;
  97. TK.data = buffer;
  98. ret = rxgk_derive_transport_key(conn, gk, rxgk, &TK, gfp);
  99. if (ret < 0)
  100. goto out;
  101. aead = crypto_krb5_prepare_encryption(krb5, &TK, RXGK_CLIENT_ENC_RESPONSE, gfp);
  102. if (IS_ERR(aead))
  103. goto aead_error;
  104. gk->resp_enc = aead;
  105. if (crypto_aead_blocksize(gk->resp_enc) != krb5->block_len ||
  106. crypto_aead_authsize(gk->resp_enc) != krb5->cksum_len) {
  107. pr_notice("algo inconsistent with krb5 table %u!=%u or %u!=%u\n",
  108. crypto_aead_blocksize(gk->resp_enc), krb5->block_len,
  109. crypto_aead_authsize(gk->resp_enc), krb5->cksum_len);
  110. ret = -EINVAL;
  111. goto out;
  112. }
  113. if (service) {
  114. switch (conn->security_level) {
  115. case RXRPC_SECURITY_AUTH:
  116. shash = crypto_krb5_prepare_checksum(
  117. krb5, &TK, RXGK_SERVER_MIC_PACKET, gfp);
  118. if (IS_ERR(shash))
  119. goto hash_error;
  120. gk->tx_Kc = shash;
  121. shash = crypto_krb5_prepare_checksum(
  122. krb5, &TK, RXGK_CLIENT_MIC_PACKET, gfp);
  123. if (IS_ERR(shash))
  124. goto hash_error;
  125. gk->rx_Kc = shash;
  126. break;
  127. case RXRPC_SECURITY_ENCRYPT:
  128. aead = crypto_krb5_prepare_encryption(
  129. krb5, &TK, RXGK_SERVER_ENC_PACKET, gfp);
  130. if (IS_ERR(aead))
  131. goto aead_error;
  132. gk->tx_enc = aead;
  133. aead = crypto_krb5_prepare_encryption(
  134. krb5, &TK, RXGK_CLIENT_ENC_PACKET, gfp);
  135. if (IS_ERR(aead))
  136. goto aead_error;
  137. gk->rx_enc = aead;
  138. break;
  139. }
  140. } else {
  141. switch (conn->security_level) {
  142. case RXRPC_SECURITY_AUTH:
  143. shash = crypto_krb5_prepare_checksum(
  144. krb5, &TK, RXGK_CLIENT_MIC_PACKET, gfp);
  145. if (IS_ERR(shash))
  146. goto hash_error;
  147. gk->tx_Kc = shash;
  148. shash = crypto_krb5_prepare_checksum(
  149. krb5, &TK, RXGK_SERVER_MIC_PACKET, gfp);
  150. if (IS_ERR(shash))
  151. goto hash_error;
  152. gk->rx_Kc = shash;
  153. break;
  154. case RXRPC_SECURITY_ENCRYPT:
  155. aead = crypto_krb5_prepare_encryption(
  156. krb5, &TK, RXGK_CLIENT_ENC_PACKET, gfp);
  157. if (IS_ERR(aead))
  158. goto aead_error;
  159. gk->tx_enc = aead;
  160. aead = crypto_krb5_prepare_encryption(
  161. krb5, &TK, RXGK_SERVER_ENC_PACKET, gfp);
  162. if (IS_ERR(aead))
  163. goto aead_error;
  164. gk->rx_enc = aead;
  165. break;
  166. }
  167. }
  168. ret = 0;
  169. out:
  170. kfree_sensitive(buffer);
  171. return ret;
  172. aead_error:
  173. ret = PTR_ERR(aead);
  174. goto out;
  175. hash_error:
  176. ret = PTR_ERR(shash);
  177. goto out;
  178. }
  179. /*
  180. * Derive a transport key for a connection and then derive a bunch of usage
  181. * keys from it and set up ciphers using them.
  182. */
  183. struct rxgk_context *rxgk_generate_transport_key(struct rxrpc_connection *conn,
  184. const struct rxgk_key *key,
  185. unsigned int key_number,
  186. gfp_t gfp)
  187. {
  188. struct rxgk_context *gk;
  189. unsigned long lifetime;
  190. int ret = -ENOPKG;
  191. _enter("");
  192. gk = kzalloc_obj(*gk);
  193. if (!gk)
  194. return ERR_PTR(-ENOMEM);
  195. refcount_set(&gk->usage, 1);
  196. gk->key = key;
  197. gk->key_number = key_number;
  198. gk->krb5 = crypto_krb5_find_enctype(key->enctype);
  199. if (!gk->krb5)
  200. goto err_tk;
  201. ret = rxgk_set_up_ciphers(conn, gk, key, gfp);
  202. if (ret)
  203. goto err_tk;
  204. /* Set the remaining number of bytes encrypted with this key that may
  205. * be transmitted before rekeying. Note that the spec has been
  206. * interpreted differently on this point...
  207. */
  208. switch (key->bytelife) {
  209. case 0:
  210. case 63:
  211. gk->bytes_remaining = LLONG_MAX;
  212. break;
  213. case 1 ... 62:
  214. gk->bytes_remaining = 1LL << key->bytelife;
  215. break;
  216. default:
  217. gk->bytes_remaining = key->bytelife;
  218. break;
  219. }
  220. /* Set the time after which rekeying must occur */
  221. if (key->lifetime) {
  222. lifetime = min_t(u64, key->lifetime, INT_MAX / HZ);
  223. lifetime *= HZ;
  224. } else {
  225. lifetime = MAX_JIFFY_OFFSET;
  226. }
  227. gk->expiry = jiffies + lifetime;
  228. return gk;
  229. err_tk:
  230. rxgk_put(gk);
  231. _leave(" = %d", ret);
  232. return ERR_PTR(ret);
  233. }
  234. /*
  235. * Use the server secret key to set up the ciphers that will be used to extract
  236. * the token from a response packet.
  237. */
  238. int rxgk_set_up_token_cipher(const struct krb5_buffer *server_key,
  239. struct crypto_aead **token_aead,
  240. unsigned int enctype,
  241. const struct krb5_enctype **_krb5,
  242. gfp_t gfp)
  243. {
  244. const struct krb5_enctype *krb5;
  245. struct crypto_aead *aead;
  246. krb5 = crypto_krb5_find_enctype(enctype);
  247. if (!krb5)
  248. return -ENOPKG;
  249. aead = crypto_krb5_prepare_encryption(krb5, server_key, RXGK_SERVER_ENC_TOKEN, gfp);
  250. if (IS_ERR(aead))
  251. return PTR_ERR(aead);
  252. *_krb5 = krb5;
  253. *token_aead = aead;
  254. return 0;
  255. }