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