From e1068a862ccaec2d6dec9580dfa00fa8a561b64c Mon Sep 17 00:00:00 2001 From: Konrad Sztyber Date: Tue, 2 Aug 2022 06:46:42 +0200 Subject: [PATCH] sma: configure crypto when attaching volumes Crypto parameters are now checked and crypto is configured when a volume is attached. Since configuring crypto can lead to creating new bdevs on top of the attached volume, each device manager will also need to be changed to retrieve the bdev through the CryptoEngine.get_crypto_bdev() interface. This will be done in subsequent patches. Signed-off-by: Konrad Sztyber Change-Id: Idb5f804cf88aa5e34bbee6817acdb8f3a42a2320 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13870 Tested-by: SPDK CI Jenkins Reviewed-by: Ben Walker Reviewed-by: Jim Harris Reviewed-by: --- python/spdk/sma/volume/volume.py | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/python/spdk/sma/volume/volume.py b/python/spdk/sma/volume/volume.py index a4be3aabf..e3a641d44 100644 --- a/python/spdk/sma/volume/volume.py +++ b/python/spdk/sma/volume/volume.py @@ -5,6 +5,7 @@ import threading import uuid from dataclasses import dataclass from spdk.rpc.client import JSONRPCException +from . import crypto from ..common import format_volume_id from ..proto import sma_pb2 @@ -157,6 +158,40 @@ class VolumeManager: raise VolumeException(grpc.StatusCode.INTERNAL, 'Failed to stop discovery') + def _get_crypto_params(self, params): + key, cipher, key2 = None, None, None + try: + if params.HasField('crypto'): + key, cipher = params.crypto.key.decode('ascii'), params.crypto.cipher + if len(params.crypto.key2) > 0: + key2 = params.crypto.key2.decode('ascii') + except UnicodeDecodeError: + raise VolumeException(grpc.StatusCode.INVALID_ARGUMENT, + 'Corrupted crypto key') + return key, cipher, key2 + + def _setup_crypto(self, volume_id, params): + try: + if not params.HasField('crypto'): + return + key, cipher, key2 = self._get_crypto_params(params) + crypto.get_crypto_engine().setup(volume_id, key, cipher, key2) + except crypto.CryptoException as ex: + raise VolumeException(ex.code, ex.message) + + def _cleanup_crypto(self, volume_id): + try: + crypto.get_crypto_engine().cleanup(volume_id) + except crypto.CryptoException as ex: + logging.warning(f'Failed to cleanup crypto: {ex.message}') + + def _verify_crypto(self, volume_id, params): + try: + key, cipher, key2 = self._get_crypto_params(params) + crypto.get_crypto_engine().verify(volume_id, key, cipher, key2) + except crypto.CryptoException as ex: + raise VolumeException(ex.code, ex.message) + @_locked def connect_volume(self, params, device_handle=None): """ Connects a volume through a discovery service. Returns a tuple (volume_id, existing): @@ -172,6 +207,8 @@ class VolumeManager: if device_handle is not None and volume.device_handle != device_handle: raise VolumeException(grpc.StatusCode.ALREADY_EXISTS, 'Volume is already attached to a different device') + # Make sure the crypto params are the same + self._verify_crypto(volume_id, params) return volume_id, True discovery_services = set() try: @@ -218,6 +255,7 @@ class VolumeManager: if subnqn != params.nvmf.subnqn: raise VolumeException(grpc.StatusCode.INVALID_ARGUMENT, 'Unexpected subsystem NQN') + self._setup_crypto(volume_id, params) # Finally remember that volume self._volumes[volume_id] = Volume(volume_id, device_handle, discovery_services) except Exception as ex: @@ -238,6 +276,7 @@ class VolumeManager: volume = self._volumes.get(id) if volume is None: return + self._cleanup_crypto(id) # Delete the volume from the map and stop the services it uses for name in volume.discovery_services: try: