cm_security.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /* Cache manager security.
  3. *
  4. * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
  5. * Written by David Howells (dhowells@redhat.com)
  6. */
  7. #include <linux/slab.h>
  8. #include <crypto/krb5.h>
  9. #include "internal.h"
  10. #include "afs_cm.h"
  11. #include "afs_fs.h"
  12. #include "protocol_yfs.h"
  13. #define RXRPC_TRACE_ONLY_DEFINE_ENUMS
  14. #include <trace/events/rxrpc.h>
  15. #define RXGK_SERVER_ENC_TOKEN 1036U // 0x40c
  16. #define xdr_round_up(x) (round_up((x), sizeof(__be32)))
  17. #define xdr_len_object(x) (4 + round_up((x), sizeof(__be32)))
  18. #ifdef CONFIG_RXGK
  19. static int afs_create_yfs_cm_token(struct sk_buff *challenge,
  20. struct afs_server *server);
  21. #endif
  22. /*
  23. * Respond to an RxGK challenge, adding appdata.
  24. */
  25. static int afs_respond_to_challenge(struct sk_buff *challenge)
  26. {
  27. #ifdef CONFIG_RXGK
  28. struct krb5_buffer appdata = {};
  29. struct afs_server *server;
  30. #endif
  31. struct rxrpc_peer *peer;
  32. unsigned long peer_data;
  33. u16 service_id;
  34. u8 security_index;
  35. rxrpc_kernel_query_challenge(challenge, &peer, &peer_data,
  36. &service_id, &security_index);
  37. _enter("%u,%u", service_id, security_index);
  38. switch (service_id) {
  39. /* We don't send CM_SERVICE RPCs, so don't expect a challenge
  40. * therefrom.
  41. */
  42. case FS_SERVICE:
  43. case VL_SERVICE:
  44. case YFS_FS_SERVICE:
  45. case YFS_VL_SERVICE:
  46. break;
  47. default:
  48. pr_warn("Can't respond to unknown challenge %u:%u",
  49. service_id, security_index);
  50. return rxrpc_kernel_reject_challenge(challenge, RX_USER_ABORT, -EPROTO,
  51. afs_abort_unsupported_sec_class);
  52. }
  53. switch (security_index) {
  54. #ifdef CONFIG_RXKAD
  55. case RXRPC_SECURITY_RXKAD:
  56. return rxkad_kernel_respond_to_challenge(challenge);
  57. #endif
  58. #ifdef CONFIG_RXGK
  59. case RXRPC_SECURITY_RXGK:
  60. return rxgk_kernel_respond_to_challenge(challenge, &appdata);
  61. case RXRPC_SECURITY_YFS_RXGK:
  62. switch (service_id) {
  63. case FS_SERVICE:
  64. case YFS_FS_SERVICE:
  65. server = (struct afs_server *)peer_data;
  66. if (!server->cm_rxgk_appdata.data) {
  67. mutex_lock(&server->cm_token_lock);
  68. if (!server->cm_rxgk_appdata.data)
  69. afs_create_yfs_cm_token(challenge, server);
  70. mutex_unlock(&server->cm_token_lock);
  71. }
  72. if (server->cm_rxgk_appdata.data)
  73. appdata = server->cm_rxgk_appdata;
  74. break;
  75. }
  76. return rxgk_kernel_respond_to_challenge(challenge, &appdata);
  77. #endif
  78. default:
  79. return rxrpc_kernel_reject_challenge(challenge, RX_USER_ABORT, -EPROTO,
  80. afs_abort_unsupported_sec_class);
  81. }
  82. }
  83. /*
  84. * Process the OOB message queue, processing challenge packets.
  85. */
  86. void afs_process_oob_queue(struct work_struct *work)
  87. {
  88. struct afs_net *net = container_of(work, struct afs_net, rx_oob_work);
  89. struct sk_buff *oob;
  90. enum rxrpc_oob_type type;
  91. while ((oob = rxrpc_kernel_dequeue_oob(net->socket, &type))) {
  92. switch (type) {
  93. case RXRPC_OOB_CHALLENGE:
  94. afs_respond_to_challenge(oob);
  95. break;
  96. }
  97. rxrpc_kernel_free_oob(oob);
  98. }
  99. }
  100. #ifdef CONFIG_RXGK
  101. /*
  102. * Create a securities keyring for the cache manager and attach a key to it for
  103. * the RxGK tokens we want to use to secure the callback connection back from
  104. * the fileserver.
  105. */
  106. int afs_create_token_key(struct afs_net *net, struct socket *socket)
  107. {
  108. const struct krb5_enctype *krb5;
  109. struct key *ring;
  110. key_ref_t key;
  111. char K0[32], *desc;
  112. int ret;
  113. ring = keyring_alloc("kafs",
  114. GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
  115. KEY_POS_SEARCH | KEY_POS_WRITE |
  116. KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH,
  117. KEY_ALLOC_NOT_IN_QUOTA,
  118. NULL, NULL);
  119. if (IS_ERR(ring))
  120. return PTR_ERR(ring);
  121. ret = rxrpc_sock_set_security_keyring(socket->sk, ring);
  122. if (ret < 0)
  123. goto out;
  124. ret = -ENOPKG;
  125. krb5 = crypto_krb5_find_enctype(KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96);
  126. if (!krb5)
  127. goto out;
  128. if (WARN_ON_ONCE(krb5->key_len > sizeof(K0)))
  129. goto out;
  130. ret = -ENOMEM;
  131. desc = kasprintf(GFP_KERNEL, "%u:%u:%u:%u",
  132. YFS_CM_SERVICE, RXRPC_SECURITY_YFS_RXGK, 1, krb5->etype);
  133. if (!desc)
  134. goto out;
  135. wait_for_random_bytes();
  136. get_random_bytes(K0, krb5->key_len);
  137. key = key_create(make_key_ref(ring, true),
  138. "rxrpc_s", desc,
  139. K0, krb5->key_len,
  140. KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_USR_VIEW,
  141. KEY_ALLOC_NOT_IN_QUOTA);
  142. kfree(desc);
  143. if (IS_ERR(key)) {
  144. ret = PTR_ERR(key);
  145. goto out;
  146. }
  147. net->fs_cm_token_key = key_ref_to_ptr(key);
  148. ret = 0;
  149. out:
  150. key_put(ring);
  151. return ret;
  152. }
  153. /*
  154. * Create an YFS RxGK GSS token to use as a ticket to the specified fileserver.
  155. */
  156. static int afs_create_yfs_cm_token(struct sk_buff *challenge,
  157. struct afs_server *server)
  158. {
  159. const struct krb5_enctype *conn_krb5, *token_krb5;
  160. const struct krb5_buffer *token_key;
  161. struct crypto_aead *aead;
  162. struct scatterlist sg;
  163. struct afs_net *net = server->cell->net;
  164. const struct key *key = net->fs_cm_token_key;
  165. size_t keysize, uuidsize, authsize, toksize, encsize, contsize, adatasize, offset;
  166. __be32 caps[1] = {
  167. [0] = htonl(AFS_CAP_ERROR_TRANSLATION),
  168. };
  169. __be32 *xdr;
  170. void *appdata, *K0, *encbase;
  171. u32 enctype;
  172. int ret;
  173. if (!key)
  174. return -ENOKEY;
  175. /* Assume that the fileserver is happy to use the same encoding type as
  176. * we were told to use by the token obtained by the user.
  177. */
  178. enctype = rxgk_kernel_query_challenge(challenge);
  179. conn_krb5 = crypto_krb5_find_enctype(enctype);
  180. if (!conn_krb5)
  181. return -ENOPKG;
  182. token_krb5 = key->payload.data[0];
  183. token_key = (const struct krb5_buffer *)&key->payload.data[2];
  184. /* struct rxgk_key {
  185. * afs_uint32 enctype;
  186. * opaque key<>;
  187. * };
  188. */
  189. keysize = 4 + xdr_len_object(conn_krb5->key_len);
  190. /* struct RXGK_AuthName {
  191. * afs_int32 kind;
  192. * opaque data<AUTHDATAMAX>;
  193. * opaque display<AUTHPRINTABLEMAX>;
  194. * };
  195. */
  196. uuidsize = sizeof(server->uuid);
  197. authsize = 4 + xdr_len_object(uuidsize) + xdr_len_object(0);
  198. /* struct RXGK_Token {
  199. * rxgk_key K0;
  200. * RXGK_Level level;
  201. * rxgkTime starttime;
  202. * afs_int32 lifetime;
  203. * afs_int32 bytelife;
  204. * rxgkTime expirationtime;
  205. * struct RXGK_AuthName identities<>;
  206. * };
  207. */
  208. toksize = keysize + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
  209. offset = 0;
  210. encsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, &offset);
  211. /* struct RXGK_TokenContainer {
  212. * afs_int32 kvno;
  213. * afs_int32 enctype;
  214. * opaque encrypted_token<>;
  215. * };
  216. */
  217. contsize = 4 + 4 + xdr_len_object(encsize);
  218. /* struct YFSAppData {
  219. * opr_uuid initiatorUuid;
  220. * opr_uuid acceptorUuid;
  221. * Capabilities caps;
  222. * afs_int32 enctype;
  223. * opaque callbackKey<>;
  224. * opaque callbackToken<>;
  225. * };
  226. */
  227. adatasize = 16 + 16 +
  228. xdr_len_object(sizeof(caps)) +
  229. 4 +
  230. xdr_len_object(conn_krb5->key_len) +
  231. xdr_len_object(contsize);
  232. ret = -ENOMEM;
  233. appdata = kzalloc(adatasize, GFP_KERNEL);
  234. if (!appdata)
  235. goto out;
  236. xdr = appdata;
  237. memcpy(xdr, &net->uuid, 16); /* appdata.initiatorUuid */
  238. xdr += 16 / 4;
  239. memcpy(xdr, &server->uuid, 16); /* appdata.acceptorUuid */
  240. xdr += 16 / 4;
  241. *xdr++ = htonl(ARRAY_SIZE(caps)); /* appdata.caps.len */
  242. memcpy(xdr, &caps, sizeof(caps)); /* appdata.caps */
  243. xdr += ARRAY_SIZE(caps);
  244. *xdr++ = htonl(conn_krb5->etype); /* appdata.enctype */
  245. *xdr++ = htonl(conn_krb5->key_len); /* appdata.callbackKey.len */
  246. K0 = xdr;
  247. get_random_bytes(K0, conn_krb5->key_len); /* appdata.callbackKey.data */
  248. xdr += xdr_round_up(conn_krb5->key_len) / 4;
  249. *xdr++ = htonl(contsize); /* appdata.callbackToken.len */
  250. *xdr++ = htonl(1); /* cont.kvno */
  251. *xdr++ = htonl(token_krb5->etype); /* cont.enctype */
  252. *xdr++ = htonl(encsize); /* cont.encrypted_token.len */
  253. encbase = xdr;
  254. xdr += offset / 4;
  255. *xdr++ = htonl(conn_krb5->etype); /* token.K0.enctype */
  256. *xdr++ = htonl(conn_krb5->key_len); /* token.K0.key.len */
  257. memcpy(xdr, K0, conn_krb5->key_len); /* token.K0.key.data */
  258. xdr += xdr_round_up(conn_krb5->key_len) / 4;
  259. *xdr++ = htonl(RXRPC_SECURITY_ENCRYPT); /* token.level */
  260. *xdr++ = htonl(0); /* token.starttime */
  261. *xdr++ = htonl(0); /* " */
  262. *xdr++ = htonl(0); /* token.lifetime */
  263. *xdr++ = htonl(0); /* token.bytelife */
  264. *xdr++ = htonl(0); /* token.expirationtime */
  265. *xdr++ = htonl(0); /* " */
  266. *xdr++ = htonl(1); /* token.identities.count */
  267. *xdr++ = htonl(0); /* token.identities[0].kind */
  268. *xdr++ = htonl(uuidsize); /* token.identities[0].data.len */
  269. memcpy(xdr, &server->uuid, uuidsize);
  270. xdr += xdr_round_up(uuidsize) / 4;
  271. *xdr++ = htonl(0); /* token.identities[0].display.len */
  272. xdr = encbase + xdr_round_up(encsize);
  273. if ((unsigned long)xdr - (unsigned long)appdata != adatasize)
  274. pr_err("Appdata size incorrect %lx != %zx\n",
  275. (unsigned long)xdr - (unsigned long)appdata, adatasize);
  276. aead = crypto_krb5_prepare_encryption(token_krb5, token_key, RXGK_SERVER_ENC_TOKEN,
  277. GFP_KERNEL);
  278. if (IS_ERR(aead)) {
  279. ret = PTR_ERR(aead);
  280. goto out_token;
  281. }
  282. sg_init_one(&sg, encbase, encsize);
  283. ret = crypto_krb5_encrypt(token_krb5, aead, &sg, 1, encsize, offset, toksize, false);
  284. if (ret < 0)
  285. goto out_aead;
  286. server->cm_rxgk_appdata.len = adatasize;
  287. server->cm_rxgk_appdata.data = appdata;
  288. appdata = NULL;
  289. out_aead:
  290. crypto_free_aead(aead);
  291. out_token:
  292. kfree(appdata);
  293. out:
  294. return ret;
  295. }
  296. #endif /* CONFIG_RXGK */