xref: /linux/net/rxrpc/rxgk_common.h (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
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 			   unsigned int ticket_offset, unsigned int ticket_len,
45 			   struct key **_key);
46 int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb,
47 		       unsigned int token_offset, 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 to part of an skbuff.  The
66  * offset and length are updated to reflect the actual content of the encrypted
67  * region.
68  */
69 static inline
70 int rxgk_decrypt_skb(const struct krb5_enctype *krb5,
71 		     struct crypto_aead *aead,
72 		     struct sk_buff *skb,
73 		     unsigned int *_offset, unsigned int *_len,
74 		     int *_error_code)
75 {
76 	struct scatterlist sg[16];
77 	size_t offset = 0, len = *_len;
78 	int nr_sg, ret;
79 
80 	sg_init_table(sg, ARRAY_SIZE(sg));
81 	nr_sg = skb_to_sgvec(skb, sg, *_offset, len);
82 	if (unlikely(nr_sg < 0))
83 		return nr_sg;
84 
85 	ret = crypto_krb5_decrypt(krb5, aead, sg, nr_sg,
86 				  &offset, &len);
87 	switch (ret) {
88 	case 0:
89 		*_offset += offset;
90 		*_len = len;
91 		break;
92 	case -EBADMSG: /* Checksum mismatch. */
93 	case -EPROTO:
94 		*_error_code = RXGK_SEALEDINCON;
95 		break;
96 	case -EMSGSIZE:
97 		*_error_code = RXGK_PACKETSHORT;
98 		break;
99 	case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */
100 	default:
101 		*_error_code = RXGK_INCONSISTENCY;
102 		break;
103 	}
104 
105 	return ret;
106 }
107 
108 /*
109  * Check the MIC on a region of an skbuff.  The offset and length are updated
110  * to reflect the actual content of the secure region.
111  */
112 static inline
113 int rxgk_verify_mic_skb(const struct krb5_enctype *krb5,
114 			struct crypto_shash *shash,
115 			const struct krb5_buffer *metadata,
116 			struct sk_buff *skb,
117 			unsigned int *_offset, unsigned int *_len,
118 			u32 *_error_code)
119 {
120 	struct scatterlist sg[16];
121 	size_t offset = 0, len = *_len;
122 	int nr_sg, ret;
123 
124 	sg_init_table(sg, ARRAY_SIZE(sg));
125 	nr_sg = skb_to_sgvec(skb, sg, *_offset, len);
126 	if (unlikely(nr_sg < 0))
127 		return nr_sg;
128 
129 	ret = crypto_krb5_verify_mic(krb5, shash, metadata, sg, nr_sg,
130 				     &offset, &len);
131 	switch (ret) {
132 	case 0:
133 		*_offset += offset;
134 		*_len = len;
135 		break;
136 	case -EBADMSG: /* Checksum mismatch */
137 	case -EPROTO:
138 		*_error_code = RXGK_SEALEDINCON;
139 		break;
140 	case -EMSGSIZE:
141 		*_error_code = RXGK_PACKETSHORT;
142 		break;
143 	case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */
144 	default:
145 		*_error_code = RXGK_INCONSISTENCY;
146 		break;
147 	}
148 
149 	return ret;
150 }
151