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 */ 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 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