1 // SPDX-License-Identifier: GPL-2.0 2 /* OpenVPN data channel offload 3 * 4 * Copyright (C) 2020-2025 OpenVPN, Inc. 5 * 6 * Author: James Yonan <james@openvpn.net> 7 * Antonio Quartulli <antonio@openvpn.net> 8 */ 9 10 #include <linux/types.h> 11 #include <linux/net.h> 12 #include <linux/netdevice.h> 13 #include <uapi/linux/ovpn.h> 14 15 #include "ovpnpriv.h" 16 #include "main.h" 17 #include "pktid.h" 18 #include "crypto_aead.h" 19 #include "crypto.h" 20 21 void ovpn_crypto_key_slot_release(struct kref *kref) 22 { 23 struct ovpn_crypto_key_slot *ks; 24 25 ks = container_of(kref, struct ovpn_crypto_key_slot, refcount); 26 queue_rcu_work(ovpn_wq, &ks->free_work); 27 } 28 29 /* can only be invoked when all peer references have been dropped (i.e. RCU 30 * release routine) 31 */ 32 void ovpn_crypto_state_release(struct ovpn_crypto_state *cs) 33 { 34 struct ovpn_crypto_key_slot *ks; 35 36 ks = rcu_access_pointer(cs->slots[0]); 37 if (ks) { 38 RCU_INIT_POINTER(cs->slots[0], NULL); 39 ovpn_crypto_key_slot_put(ks); 40 } 41 42 ks = rcu_access_pointer(cs->slots[1]); 43 if (ks) { 44 RCU_INIT_POINTER(cs->slots[1], NULL); 45 ovpn_crypto_key_slot_put(ks); 46 } 47 } 48 49 /* removes the key matching the specified id from the crypto context */ 50 bool ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id) 51 { 52 struct ovpn_crypto_key_slot *ks = NULL; 53 struct ovpn_crypto_key_slot *tmp; 54 int slot = 0; 55 56 spin_lock_bh(&cs->lock); 57 tmp = rcu_access_pointer(cs->slots[slot]); 58 if (!tmp || tmp->key_id != key_id) { 59 slot = 1; 60 tmp = rcu_access_pointer(cs->slots[slot]); 61 } 62 63 if (tmp && tmp->key_id == key_id) 64 ks = rcu_replace_pointer(cs->slots[slot], NULL, 65 lockdep_is_held(&cs->lock)); 66 spin_unlock_bh(&cs->lock); 67 68 if (ks) 69 ovpn_crypto_key_slot_put(ks); 70 71 /* let the caller know if a key was actually killed */ 72 return ks; 73 } 74 75 /* Reset the ovpn_crypto_state object in a way that is atomic 76 * to RCU readers. 77 */ 78 int ovpn_crypto_state_reset(struct ovpn_crypto_state *cs, 79 const struct ovpn_peer_key_reset *pkr) 80 { 81 struct ovpn_crypto_key_slot *old = NULL, *new; 82 u8 idx; 83 84 if (pkr->slot != OVPN_KEY_SLOT_PRIMARY && 85 pkr->slot != OVPN_KEY_SLOT_SECONDARY) 86 return -EINVAL; 87 88 new = ovpn_aead_crypto_key_slot_new(&pkr->key); 89 if (IS_ERR(new)) 90 return PTR_ERR(new); 91 92 spin_lock_bh(&cs->lock); 93 idx = cs->primary_idx; 94 switch (pkr->slot) { 95 case OVPN_KEY_SLOT_PRIMARY: 96 old = rcu_replace_pointer(cs->slots[idx], new, 97 lockdep_is_held(&cs->lock)); 98 break; 99 case OVPN_KEY_SLOT_SECONDARY: 100 old = rcu_replace_pointer(cs->slots[!idx], new, 101 lockdep_is_held(&cs->lock)); 102 break; 103 } 104 spin_unlock_bh(&cs->lock); 105 106 if (old) 107 ovpn_crypto_key_slot_put(old); 108 109 return 0; 110 } 111 112 void ovpn_crypto_key_slot_delete(struct ovpn_crypto_state *cs, 113 enum ovpn_key_slot slot) 114 { 115 struct ovpn_crypto_key_slot *ks = NULL; 116 u8 idx; 117 118 if (slot != OVPN_KEY_SLOT_PRIMARY && 119 slot != OVPN_KEY_SLOT_SECONDARY) { 120 pr_warn("Invalid slot to release: %u\n", slot); 121 return; 122 } 123 124 spin_lock_bh(&cs->lock); 125 idx = cs->primary_idx; 126 switch (slot) { 127 case OVPN_KEY_SLOT_PRIMARY: 128 ks = rcu_replace_pointer(cs->slots[idx], NULL, 129 lockdep_is_held(&cs->lock)); 130 break; 131 case OVPN_KEY_SLOT_SECONDARY: 132 ks = rcu_replace_pointer(cs->slots[!idx], NULL, 133 lockdep_is_held(&cs->lock)); 134 break; 135 } 136 spin_unlock_bh(&cs->lock); 137 138 if (!ks) { 139 pr_debug("Key slot already released: %u\n", slot); 140 return; 141 } 142 143 pr_debug("deleting key slot %u, key_id=%u\n", slot, ks->key_id); 144 ovpn_crypto_key_slot_put(ks); 145 } 146 147 void ovpn_crypto_key_slots_swap(struct ovpn_crypto_state *cs) 148 { 149 const struct ovpn_crypto_key_slot *old_primary, *old_secondary; 150 u8 idx; 151 152 spin_lock_bh(&cs->lock); 153 idx = cs->primary_idx; 154 old_primary = rcu_dereference_protected(cs->slots[idx], 155 lockdep_is_held(&cs->lock)); 156 old_secondary = rcu_dereference_protected(cs->slots[!idx], 157 lockdep_is_held(&cs->lock)); 158 /* perform real swap by switching the index of the primary key */ 159 WRITE_ONCE(cs->primary_idx, !cs->primary_idx); 160 161 pr_debug("key swapped: (old primary) %d <-> (new primary) %d\n", 162 old_primary ? old_primary->key_id : -1, 163 old_secondary ? old_secondary->key_id : -1); 164 165 spin_unlock_bh(&cs->lock); 166 } 167 168 /** 169 * ovpn_crypto_config_get - populate keyconf object with non-sensible key data 170 * @cs: the crypto state to extract the key data from 171 * @slot: the specific slot to inspect 172 * @keyconf: the output object to populate 173 * 174 * Return: 0 on success or a negative error code otherwise 175 */ 176 int ovpn_crypto_config_get(struct ovpn_crypto_state *cs, 177 enum ovpn_key_slot slot, 178 struct ovpn_key_config *keyconf) 179 { 180 struct ovpn_crypto_key_slot *ks; 181 int idx; 182 183 switch (slot) { 184 case OVPN_KEY_SLOT_PRIMARY: 185 idx = cs->primary_idx; 186 break; 187 case OVPN_KEY_SLOT_SECONDARY: 188 idx = !cs->primary_idx; 189 break; 190 default: 191 return -EINVAL; 192 } 193 194 rcu_read_lock(); 195 ks = rcu_dereference(cs->slots[idx]); 196 if (!ks) { 197 rcu_read_unlock(); 198 return -ENOENT; 199 } 200 201 keyconf->cipher_alg = ovpn_aead_crypto_alg(ks); 202 keyconf->key_id = ks->key_id; 203 rcu_read_unlock(); 204 205 return 0; 206 } 207