1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /* Common bits for GSSAPI-based RxRPC security.
3 *
4 * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 */
7
8 #include <crypto/krb5.h>
9 #include <crypto/skcipher.h>
10 #include <crypto/hash.h>
11
12 /*
13 * Per-key number context. This is replaced when the connection is rekeyed.
14 */
15 struct rxgk_context {
16 refcount_t usage;
17 unsigned int key_number; /* Rekeying number (goes in the rx header) */
18 unsigned long flags;
19 #define RXGK_TK_NEEDS_REKEY 0 /* Set if this needs rekeying */
20 unsigned long expiry; /* Expiration time of this key */
21 long long bytes_remaining; /* Remaining Tx lifetime of this key */
22 const struct krb5_enctype *krb5; /* RxGK encryption type */
23 const struct rxgk_key *key;
24
25 /* We need up to 7 keys derived from the transport key, but we don't
26 * actually need the transport key. Each key is derived by
27 * DK(TK,constant).
28 */
29 struct crypto_aead *tx_enc; /* Transmission key */
30 struct crypto_aead *rx_enc; /* Reception key */
31 struct crypto_shash *tx_Kc; /* Transmission checksum key */
32 struct crypto_shash *rx_Kc; /* Reception checksum key */
33 struct crypto_aead *resp_enc; /* Response packet enc key */
34 };
35
36 #define xdr_round_up(x) (round_up((x), sizeof(__be32)))
37 #define xdr_round_down(x) (round_down((x), sizeof(__be32)))
38 #define xdr_object_len(x) (4 + xdr_round_up(x))
39
40 /*
41 * rxgk_app.c
42 */
43 int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb,
44 void *ticket, unsigned int ticket_len,
45 struct key **_key);
46 int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb,
47 void *token, unsigned int token_len,
48 struct key **_key);
49
50 /*
51 * rxgk_kdf.c
52 */
53 void rxgk_put(struct rxgk_context *gk);
54 struct rxgk_context *rxgk_generate_transport_key(struct rxrpc_connection *conn,
55 const struct rxgk_key *key,
56 unsigned int key_number,
57 gfp_t gfp);
58 int rxgk_set_up_token_cipher(const struct krb5_buffer *server_key,
59 struct crypto_aead **token_key,
60 unsigned int enctype,
61 const struct krb5_enctype **_krb5,
62 gfp_t gfp);
63
64 /*
65 * Apply decryption and checksumming functions a flat data buffer. The data
66 * point and length are updated to reflect the actual content of the encrypted
67 * region.
68 */
rxgk_decrypt(const struct krb5_enctype * krb5,struct crypto_aead * aead,void ** _data,unsigned int * _len,int * _error_code)69 static inline int rxgk_decrypt(const struct krb5_enctype *krb5,
70 struct crypto_aead *aead,
71 void **_data, unsigned int *_len,
72 int *_error_code)
73 {
74 struct scatterlist sg[1];
75 size_t offset = 0, len = *_len;
76 int ret;
77
78 sg_init_one(sg, *_data, len);
79
80 ret = crypto_krb5_decrypt(krb5, aead, sg, 1, &offset, &len);
81 switch (ret) {
82 case 0:
83 if (offset & 3) {
84 *_error_code = RXGK_INCONSISTENCY;
85 ret = -EPROTO;
86 break;
87 }
88 *_data += offset;
89 *_len = len;
90 break;
91 case -EBADMSG: /* Checksum mismatch. */
92 case -EPROTO:
93 *_error_code = RXGK_SEALEDINCON;
94 break;
95 case -EMSGSIZE:
96 *_error_code = RXGK_PACKETSHORT;
97 break;
98 case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */
99 default:
100 *_error_code = RXGK_INCONSISTENCY;
101 break;
102 }
103
104 return ret;
105 }
106
107 /*
108 * Check the MIC on a flat buffer. The data pointer and length are updated to
109 * reflect the actual content of the secure region.
110 */
111 static inline
rxgk_verify_mic(const struct krb5_enctype * krb5,struct crypto_shash * shash,const struct krb5_buffer * metadata,void ** _data,unsigned int * _len,u32 * _error_code)112 int rxgk_verify_mic(const struct krb5_enctype *krb5,
113 struct crypto_shash *shash,
114 const struct krb5_buffer *metadata,
115 void **_data, unsigned int *_len,
116 u32 *_error_code)
117 {
118 struct scatterlist sg[1];
119 size_t offset = 0, len = *_len;
120 int ret;
121
122 sg_init_one(sg, *_data, len);
123
124 ret = crypto_krb5_verify_mic(krb5, shash, metadata, sg, 1, &offset, &len);
125 switch (ret) {
126 case 0:
127 *_data += offset;
128 *_len = len;
129 break;
130 case -EBADMSG: /* Checksum mismatch */
131 case -EPROTO:
132 *_error_code = RXGK_SEALEDINCON;
133 break;
134 case -EMSGSIZE:
135 *_error_code = RXGK_PACKETSHORT;
136 break;
137 case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */
138 default:
139 *_error_code = RXGK_INCONSISTENCY;
140 break;
141 }
142
143 return ret;
144 }
145