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_object_len(x) (4 + xdr_round_up(x))
38
39 /*
40 * rxgk_app.c
41 */
42 int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb,
43 unsigned int ticket_offset, unsigned int ticket_len,
44 struct key **_key);
45 int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb,
46 unsigned int token_offset, unsigned int token_len,
47 struct key **_key);
48
49 /*
50 * rxgk_kdf.c
51 */
52 void rxgk_put(struct rxgk_context *gk);
53 struct rxgk_context *rxgk_generate_transport_key(struct rxrpc_connection *conn,
54 const struct rxgk_key *key,
55 unsigned int key_number,
56 gfp_t gfp);
57 int rxgk_set_up_token_cipher(const struct krb5_buffer *server_key,
58 struct crypto_aead **token_key,
59 unsigned int enctype,
60 const struct krb5_enctype **_krb5,
61 gfp_t gfp);
62
63 /*
64 * Apply decryption and checksumming functions to part of an skbuff. The
65 * offset and length are updated to reflect the actual content of the encrypted
66 * region.
67 */
68 static inline
rxgk_decrypt_skb(const struct krb5_enctype * krb5,struct crypto_aead * aead,struct sk_buff * skb,unsigned int * _offset,unsigned int * _len,int * _error_code)69 int rxgk_decrypt_skb(const struct krb5_enctype *krb5,
70 struct crypto_aead *aead,
71 struct sk_buff *skb,
72 unsigned int *_offset, unsigned int *_len,
73 int *_error_code)
74 {
75 struct scatterlist sg[16];
76 size_t offset = 0, len = *_len;
77 int nr_sg, ret;
78
79 sg_init_table(sg, ARRAY_SIZE(sg));
80 nr_sg = skb_to_sgvec(skb, sg, *_offset, len);
81 if (unlikely(nr_sg < 0))
82 return nr_sg;
83
84 ret = crypto_krb5_decrypt(krb5, aead, sg, nr_sg,
85 &offset, &len);
86 switch (ret) {
87 case 0:
88 *_offset += 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 region of an skbuff. The offset and length are updated
109 * to reflect the actual content of the secure region.
110 */
111 static inline
rxgk_verify_mic_skb(const struct krb5_enctype * krb5,struct crypto_shash * shash,const struct krb5_buffer * metadata,struct sk_buff * skb,unsigned int * _offset,unsigned int * _len,u32 * _error_code)112 int rxgk_verify_mic_skb(const struct krb5_enctype *krb5,
113 struct crypto_shash *shash,
114 const struct krb5_buffer *metadata,
115 struct sk_buff *skb,
116 unsigned int *_offset, unsigned int *_len,
117 u32 *_error_code)
118 {
119 struct scatterlist sg[16];
120 size_t offset = 0, len = *_len;
121 int nr_sg, ret;
122
123 sg_init_table(sg, ARRAY_SIZE(sg));
124 nr_sg = skb_to_sgvec(skb, sg, *_offset, len);
125 if (unlikely(nr_sg < 0))
126 return nr_sg;
127
128 ret = crypto_krb5_verify_mic(krb5, shash, metadata, sg, nr_sg,
129 &offset, &len);
130 switch (ret) {
131 case 0:
132 *_offset += offset;
133 *_len = len;
134 break;
135 case -EBADMSG: /* Checksum mismatch */
136 case -EPROTO:
137 *_error_code = RXGK_SEALEDINCON;
138 break;
139 case -EMSGSIZE:
140 *_error_code = RXGK_PACKETSHORT;
141 break;
142 case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */
143 default:
144 *_error_code = RXGK_INCONSISTENCY;
145 break;
146 }
147
148 return ret;
149 }
150