[PATCH v1] virtio-blk: Add inline encryption support
Linlin Zhang <[email protected]>
| Newsgroups | dev.linux.lists.virtio-dev |
|---|---|
| Message-ID | <[email protected]> |
From: linlzhan <[email protected]> Add VIRTIO_BLK_F_IE to advertise inline encryption support. When the feature is negotiated, the device reports inline encryption characteristics through virtio_blk_enc_characteristics. Add VIRTIO_BLK_T_GET_CRYPTO_MODES, VIRTIO_BLK_T_CRYPTO_IN, and VIRTIO_BLK_T_CRYPTO_OUT so that the driver can discover supported crypto modes and submit inline-encrypted I/O requests. Crypto I/O requests carry a virtual key slot index, data unit size, and initial Data Unit Number (DUN). The device maps the virtual key slot to a physical key slot in the storage backend and uses these parameters for inline encryption or decryption. Key provisioning is performed through an out-of-band mechanism and is outside the scope of this device type. For background on inline encryption in UFS and eMMC storage, see: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/block/inline-encryption.rst Change-Id: I83c52456bc0c9dd37f39ff46e6bfe73a715138ca Signed-off-by: linlzhan <[email protected]> Fixes: https://github.com/oasis-tcs/virtio-spec/issues/238 --- device-types/blk/description.tex | 297 ++++++++++++++++++++++++++++++- 1 file changed, 291 insertions(+), 6 deletions(-) diff --git a/device-types/blk/description.tex b/device-types/blk/description.tex index 3b3a4e7..f8a544b 100644 --- a/device-types/blk/description.tex +++ b/device-types/blk/description.tex @@ -71,7 +71,16 @@ \subsection{Feature bits}\label{sec:Device Types / Block Device / Feature bits} \item[VIRTIO_BLK_F_REQ_FLAGS_OUT_FUA (19)] Device supports the VIRTIO_BLK_REQ_FLAG_OUT_FUA flag in the \field{flags} bitfield of the - \field{virtio_blk_req} structure for VIRTIO_BLK_T_OUT requests. + request for VIRTIO_BLK_T_OUT and VIRTIO_BLK_T_CRYPTO_OUT requests. + +\item[VIRTIO_BLK_F_IE (22)] Only when the storage backend supports inline + encryption and this feature bit is negotiated, the data read from or + written to the device can be decrypted from or encrypted to the storage + via inline crypto engine. Keys are provisioned into key slots of the + inline crypto engine through a mechanism outside the scope of this device + type, and requests identify, by key slot index, which provisioned key to + use. The number of key slots, the maximum DUN size and the supported key + types are reported in \field{enc_characteristics}. \end{description} @@ -135,6 +144,12 @@ \subsection{Device configuration layout}\label{sec:Device Types / Block Device / u8 model; u8 unused2[3]; } zoned; + struct virtio_blk_enc_characteristics { + le16 max_slots; + u8 max_dun_bytes; + u8 key_types; + le32 unused3; + } enc_characteristics; }; \end{lstlisting} @@ -222,6 +237,39 @@ \subsection{Device configuration layout}\label{sec:Device Types / Block Device / terminated by the device with a "zone resources exceeded" error as defined for specific commands later. +If the VIRTIO_BLK_F_IE feature is negotiated, then in +\field{virtio_blk_enc_characteristics}, +\begin{itemize} +\item \field{max_slots} is the number of key slots allocated to the Guest VM. + It MUST not exceed the number of key slots supported by the inline crypto + engine of the device backend storage. Key slots are indexed from 0 to + \field{max_slots} - 1. + +\item \field{max_dun_bytes} is the maximum number of bytes of the Data Unit + Number (DUN) that the device supports for any of its supported crypto + modes. For example, known inline crypto engines report a + \field{max_dun_bytes} of 4 (JEDEC eMMC Command Queue Host Controller + Interface, CQHCI) or 8 (JEDEC UFS Host Controller Interface, UFSHCI); + a device backed by different inline crypto engine hardware MAY report + a different value, subject to the constraints in + \ref{devicenormative:Device Types / Block Device / Device Initialization}. + +\item \field{key_types} is a bitmask of the key types the device supports, + using the following values: + \begin{lstlisting} +#define VIRTIO_BLK_CRYPTO_KEY_TYPE_RAW (1 << 0) +#define VIRTIO_BLK_CRYPTO_KEY_TYPE_HW_WRAPPED (1 << 1) + \end{lstlisting} + VIRTIO_BLK_CRYPTO_KEY_TYPE_RAW indicates that keys are provisioned into + key slots in raw (plaintext) form. VIRTIO_BLK_CRYPTO_KEY_TYPE_HW_WRAPPED + indicates that the key exists only in ephemerally-wrapped form in memory + outside of dedicated hardware, and can only be unwrapped and provisioned + into key slots by dedicated hardware (e.g. a hardware key manager). The + plaintext key never exists in software-accessible memory. + +\item \field{unused3} is reserved for future use. +\end{itemize} + \subsubsection{Legacy Interface: Device configuration layout}\label{sec:Device Types / Block Device / Device configuration layout / Legacy Interface: Device configuration layout} When using the legacy interface, transitional devices and drivers MUST format the fields in struct virtio_blk_config @@ -285,6 +333,14 @@ \subsection{Device Initialization}\label{sec:Device Types / Block Device / Devic \field{zoned} can be read by the driver to determine the zone characteristics of the device. All \field{zoned} fields are read-only. +\item If the VIRTIO_BLK_F_IE feature is negotiated, the fields in + \field{enc_characteristics} can be read by the driver to determine the + inline encryption capabilities of the device, and a + VIRTIO_BLK_T_GET_CRYPTO_MODES request (see + \ref{sec:Device Types / Block Device / Device Operation}) can be sent + to retrieve the set of supported crypto modes. All + \field{enc_characteristics} fields are read-only. + \end{enumerate} \drivernormative{\subsubsection}{Device Initialization}{Device Types / Block Device / Device Initialization} @@ -312,6 +368,10 @@ \subsection{Device Initialization}\label{sec:Device Types / Block Device / Devic offered by the device with the VIRTIO_BLK_Z_HA or VIRTIO_BLK_Z_NONE zone model, then the driver MAY negotiate these two bits independently. +Zoned devices do not support inline encryption. If the VIRTIO_BLK_F_ZONED +feature is offered by the device, then the VIRTIO_BLK_F_IE feature MUST NOT +be negotiated by the driver. + If the VIRTIO_BLK_F_ZONED feature is negotiated, then \begin{itemize} \item if the driver that can not support host-managed zoned devices @@ -327,6 +387,12 @@ \subsection{Device Initialization}\label{sec:Device Types / Block Device / Devic The driver MUST NOT negotiate VIRTIO_BLK_F_REQ_FLAGS_OUT_FUA without VIRTIO_BLK_F_REQ_FLAGS. +Drivers MUST NOT negotiate the VIRTIO_BLK_F_IE feature if they are +incapable of provisioning keys into the key slots of the device backend +storage's inline crypto engine, or of conveying the key slot index, +data unit size in bits, and Data Unit Number (DUN) per request to +the device using the \field{virtio_blk_crypto_msg} structure. + \devicenormative{\subsubsection}{Device Initialization}{Device Types / Block Device / Device Initialization} Devices SHOULD always offer VIRTIO_BLK_F_FLUSH, and MUST offer it @@ -341,9 +407,15 @@ \subsection{Device Initialization}\label{sec:Device Types / Block Device / Devic If the device that is being initialized is a not a zoned device, the device SHOULD NOT offer the VIRTIO_BLK_F_ZONED feature. +A zoned device MUST NOT offer the VIRTIO_BLK_F_IE feature. + The VIRTIO_BLK_F_ZONED feature cannot be properly negotiated without FEATURES_OK bit. Legacy devices MUST NOT offer VIRTIO_BLK_F_ZONED feature bit. +The VIRTIO_BLK_F_IE feature cannot be properly negotiated without +FEATURES_OK bit. Legacy devices MUST NOT offer the VIRTIO_BLK_F_IE feature +bit. + If the VIRTIO_BLK_F_ZONED feature is not accepted by the driver, \begin{itemize} \item the device with the VIRTIO_BLK_Z_HA or VIRTIO_BLK_Z_NONE zone model SHOULD @@ -415,6 +487,26 @@ \subsection{Device Initialization}\label{sec:Device Types / Block Device / Devic The device MUST NOT acknowledge FEATURES_OK if the driver sets VIRTIO_BLK_F_REQ_FLAGS_OUT_FUA without VIRTIO_BLK_F_REQ_FLAGS. +The device MUST NOT acknowledge FEATURES_OK if the driver negotiates both +VIRTIO_BLK_F_ZONED and VIRTIO_BLK_F_IE. + +If the device is incapable of consuming the \field{virtio_blk_crypto_msg}, +the device SHOULD NOT offer the VIRTIO_BLK_F_IE feature. + +If the VIRTIO_BLK_F_IE feature is negotiated, the device MUST set +\field{max_slots} in \field{enc_characteristics} to a value greater than 0. + +If the VIRTIO_BLK_F_IE feature is negotiated, the device MUST set +\field{key_types} in \field{enc_characteristics} to have at least one of +VIRTIO_BLK_CRYPTO_KEY_TYPE_RAW or VIRTIO_BLK_CRYPTO_KEY_TYPE_HW_WRAPPED +set, and MUST NOT set any bit in \field{key_types} other than +VIRTIO_BLK_CRYPTO_KEY_TYPE_RAW and VIRTIO_BLK_CRYPTO_KEY_TYPE_HW_WRAPPED. +The device MUST initialize padding bytes \field{unused3} to 0. + +The device MUST NOT set \field{max_dun_bytes} in \field{enc_characteristics} +to 0 or to a value greater than 8, since \field{dun} of +\field{virtio_blk_crypto_msg} is a fixed 8-byte field. + \subsubsection{Legacy Interface: Device Initialization}\label{sec:Device Types / Block Device / Device Initialization / Legacy Interface: Device Initialization} Because legacy devices do not have FEATURES_OK, transitional devices @@ -478,8 +570,8 @@ \subsection{Device Operation}\label{sec:Device Types / Block Device / Device Ope value is the bit index in the \field{flags} bitfield): \begin{description} -\item[VIRTIO_BLK_REQ_FLAG_OUT_FUA (0) for VIRTIO_BLK_T_OUT requests] Force Unit - Access (FUA) flag. +\item[VIRTIO_BLK_REQ_FLAG_OUT_FUA (0) for VIRTIO_BLK_T_OUT and + VIRTIO_BLK_T_CRYPTO_OUT requests] Force Unit Access (FUA) flag. \end{description} The \field{sector} number indicates the offset (multiplied by 512) where @@ -886,6 +978,108 @@ \subsection{Device Operation}\label{sec:Device Types / Block Device / Device Ope operation by setting the VIRTIO_BLK_S_ZONE_INVALID_CMD value in \field{status} of \field{virtio_blk_req} structure. +The following requirements only apply if the VIRTIO_BLK_F_IE feature is +negotiated. + +In addition to the request types defined for devices without inline +encryption support, the type of the request can be an inline-encrypted read +(VIRTIO_BLK_T_CRYPTO_IN), an inline-encrypted write (VIRTIO_BLK_T_CRYPTO_OUT) +or a get crypto modes command (VIRTIO_BLK_T_GET_CRYPTO_MODES). + +\begin{lstlisting} +#define VIRTIO_BLK_T_CRYPTO_OUT 27 +#define VIRTIO_BLK_T_CRYPTO_IN 28 +#define VIRTIO_BLK_T_GET_CRYPTO_MODES 30 +\end{lstlisting} + +VIRTIO_BLK_T_CRYPTO_IN and VIRTIO_BLK_T_CRYPTO_OUT requests behave the same +as VIRTIO_BLK_T_IN and VIRTIO_BLK_T_OUT requests respectively, except that +the data in \field{data} is decrypted (for VIRTIO_BLK_T_CRYPTO_IN) or is to +be encrypted (for VIRTIO_BLK_T_CRYPTO_OUT) by the inline crypto engine in +the device backend storage using the key already provisioned in the key +slot identified by the request, combined with the request's Data Unit +Number (DUN). For this reason, the VIRTIO_BLK_T_CRYPTO_IN and +VIRTIO_BLK_T_CRYPTO_OUT requests have the layout that is extended to have +the \field{crypto_msg} field to carry this information: + +\begin{lstlisting} +struct virtio_blk_req_crypto { + le32 type; + le32 flags; + le64 sector; + struct virtio_blk_crypto_msg crypto_msg; + u8 data[]; + u8 status; +}; +\end{lstlisting} + +\field{crypto_msg} has the following structure: + +\begin{lstlisting} +struct virtio_blk_crypto_msg { + le32 slot; + le32 data_unit_size_bits; + le64 dun; +}; +\end{lstlisting} + +\field{slot} is the virtual key slot index, in the range from 0 to +\field{max_slots} - 1 of \field{enc_characteristics}. The device maps this +virtual key slot index to a physical key slot in the inline crypto engine of +the device backend storage. +\field{data_unit_size_bits} is $log_2$ of the data unit size in bytes, +used for calculating DUNs for sub-requests if the request is split. +\field{dun} is the Data Unit Number, that is, the initial value that the +inline crypto engine increments by one for each successive data unit of +the size specified by \field{data_unit_size_bits}, while encrypting or +decrypting the data of the request. + +VIRTIO_BLK_T_GET_CRYPTO_MODES is a read request that returns the data unit +sizes with which each of the device's crypto modes can be used. The +response consists of a header followed by zero or more \field{le32} +bitmask elements, indexed by crypto mode number: + +\begin{lstlisting} +struct virtio_blk_crypto_modes { + le32 nr_modes; + u8 reserved[4]; + le32 modes[]; +}; +\end{lstlisting} + +The device sets \field{nr_modes} in the response header to the number of +fully transferred \field{modes} elements in the data buffer. \field{modes[N]}, +for crypto mode number N, is a bitmask indicating the data unit sizes with +which crypto mode N can be used by the device: the i'th bit of +\field{modes[N]} is set if crypto mode N can be used with a data unit size +of $(1 << i)$ bytes. A value of 0 for a \field{modes} element indicates +that the device does not support the corresponding crypto mode at all. +Crypto mode number 0 is reserved; \field{modes[0]} is always set to 0 by +the device. + +Crypto mode numbers are assigned by this specification, independently of +any operating system's internal representation of crypto algorithms, so +that support for additional crypto modes can be added in future revisions +of this specification without changing the meaning of previously assigned +numbers: + +\begin{lstlisting} +#define VIRTIO_BLK_CRYPTO_MODE_AES_256_XTS 1 +#define VIRTIO_BLK_CRYPTO_MODE_AES_128_CBC_ESSIV 2 +#define VIRTIO_BLK_CRYPTO_MODE_ADIANTUM 3 +#define VIRTIO_BLK_CRYPTO_MODE_SM4_XTS 4 +\end{lstlisting} + +A driver or device implementation MAY support only a subset of these +crypto modes. Crypto mode numbers already assigned by this or an earlier +version of this specification are never reused for a different crypto +mode; additional crypto modes are assigned new numbers, greater than the +highest number defined by the version of this specification the +implementation supports. + +VIRTIO_BLK_T_CRYPTO_IN and VIRTIO_BLK_T_GET_CRYPTO_MODES requests are reads, +and VIRTIO_BLK_T_CRYPTO_OUT requests are writes. + \drivernormative{\subsubsection}{Device Operation}{Device Types / Block Device / Device Operation} The driver SHOULD check if the content of the \field{capacity} field has @@ -904,8 +1098,8 @@ \subsection{Device Operation}\label{sec:Device Types / Block Device / Device Ope A driver MUST set \field{sector} to 0 for a VIRTIO_BLK_T_FLUSH request. A driver SHOULD NOT include any data in a VIRTIO_BLK_T_FLUSH request. -The length of \field{data} MUST be a multiple of 512 bytes for VIRTIO_BLK_T_IN -and VIRTIO_BLK_T_OUT requests. +The length of \field{data} MUST be a multiple of 512 bytes for VIRTIO_BLK_T_IN, +VIRTIO_BLK_T_OUT, VIRTIO_BLK_T_CRYPTO_IN and VIRTIO_BLK_T_CRYPTO_OUT requests. The length of \field{data} MUST be a multiple of the size of struct virtio_blk_discard_write_zeroes for VIRTIO_BLK_T_DISCARD, @@ -984,6 +1178,42 @@ \subsection{Device Operation}\label{sec:Device Types / Block Device / Device Ope \end{enumerate} +The following requirements only apply if the VIRTIO_BLK_F_IE feature is +negotiated. + +A driver MUST NOT submit a VIRTIO_BLK_T_CRYPTO_IN or VIRTIO_BLK_T_CRYPTO_OUT +request with a \field{slot} value that is not less than \field{max_slots} of +\field{enc_characteristics}, or that identifies a key slot into which no key +has been provisioned. + +A driver MUST set \field{data_unit_size_bits} of a VIRTIO_BLK_T_CRYPTO_IN or +VIRTIO_BLK_T_CRYPTO_OUT request's \field{crypto_msg} to $log_2$ of the data +unit size in bytes associated with the key provisioned in the virtual key +slot identified by \field{slot}. Since data unit sizes are reported by +VIRTIO_BLK_T_GET_CRYPTO_MODES as a bitmask of \field{le32} elements, a +driver MUST NOT set \field{data_unit_size_bits} to a value greater than 31. + +A driver MUST NOT submit a VIRTIO_BLK_T_CRYPTO_IN or VIRTIO_BLK_T_CRYPTO_OUT +request with a zero length \field{data}. + +A driver MUST NOT submit a VIRTIO_BLK_T_CRYPTO_IN or VIRTIO_BLK_T_CRYPTO_OUT +request unless \field{sector}, multiplied by 512, and the length of +\field{data}, are both a multiple of $(1 << \field{data_unit_size_bits})$ +bytes. + +A driver MUST NOT submit a VIRTIO_BLK_T_CRYPTO_IN or VIRTIO_BLK_T_CRYPTO_OUT +request if \field{dun} + $N$ - 1 is not representable in +\field{max_dun_bytes} bytes, where $N$ is the number of data units of +$2^{\field{data_unit_size_bits}}$ bytes in \field{data}. + +A driver MUST treat any crypto mode number that is not less than +\field{nr_modes} of a VIRTIO_BLK_T_GET_CRYPTO_MODES response as unsupported +by the device. + +A driver MUST provide a \field{data} buffer of at least +sizeof(struct virtio_blk_crypto_modes) (8) bytes for a +VIRTIO_BLK_T_GET_CRYPTO_MODES request. + \devicenormative{\subsubsection}{Device Operation}{Device Types / Block Device / Device Operation} The device MAY change the content of the \field{capacity} field during @@ -1030,7 +1260,8 @@ \subsection{Device Operation}\label{sec:Device Types / Block Device / Device Ope \item\label{item:flush3} the VIRTIO_BLK_F_REQ_FLAGS_OUT_FUA feature was negotiated and the VIRTIO_BLK_REQ_FLAG_OUT_FUA bit in \field{flags} was set in - the write request (regardless of whether the VIRTIO_BLK_F_FLUSH or + the write request (VIRTIO_BLK_T_OUT or VIRTIO_BLK_T_CRYPTO_OUT, regardless of + whether the VIRTIO_BLK_F_FLUSH or VIRTIO_BLK_F_CONFIG_WCE features were negotiated, and regardless of the current cache mode as expressed by the value of the \field{writeback} field in configuration space). @@ -1225,6 +1456,60 @@ \subsection{Device Operation}\label{sec:Device Types / Block Device / Device Ope handles VIRTIO_BLK_T_ZONE_RESET request for the zone range specified in the VIRTIO_BLK_T_SECURE_ERASE request. +The following requirements only apply if the VIRTIO_BLK_F_IE feature is +negotiated. + +If a VIRTIO_BLK_T_CRYPTO_IN or VIRTIO_BLK_T_CRYPTO_OUT request: +\begin{itemize} +\item specifies a \field{slot} value that is not less than \field{max_slots}, + or that identifies a key slot into which no key has been provisioned, + +\item specifies a \field{data_unit_size_bits} value greater than 31, or + that does not match $log_2$ of the data unit size in bytes associated + with the key provisioned in the virtual key slot identified by the + \field{slot}, + +\item specifies a zero length \field{data}, + +\item specifies a \field{sector}, multiplied by 512, or a length of + \field{data}, that is not a multiple of $(1 << \field{data_unit_size_bits})$ + bytes, or + +\item specifies a \field{dun} such that \field{dun} + $N$ - 1 is not + representable in \field{max_dun_bytes} bytes, where $N$ is the number + of data units of $2^{\field{data_unit_size_bits}}$ bytes in + \field{data}, +\end{itemize} +then the device MUST set the \field{status} byte to VIRTIO_BLK_S_UNSUPP and +MUST NOT read or write any data. + +If a VIRTIO_BLK_T_GET_CRYPTO_MODES request's \field{data} buffer is smaller +than sizeof(struct virtio_blk_crypto_modes) (8) bytes, the device MUST set +the \field{status} byte to VIRTIO_BLK_S_UNSUPP and MUST NOT write any data. + +If the driver's \field{data} buffer in a VIRTIO_BLK_T_GET_CRYPTO_MODES +request is not large enough to hold \field{modes} elements up to the +highest crypto mode number the device supports, the device MUST set +\field{nr_modes} to the number of complete \field{modes} elements that fit +in the buffer, and MUST NOT write a partial element. + +The device MUST initialize padding bytes \field{reserved} of a +VIRTIO_BLK_T_GET_CRYPTO_MODES response to 0. + +For a VIRTIO_BLK_T_CRYPTO_IN or VIRTIO_BLK_T_CRYPTO_OUT request, the device +MUST use the key provisioned in the virtual key slot identified by +\field{slot} of the request's \field{crypto_msg}, combined with \field{dun}, +to decrypt the data read from, or encrypt the data written to, the device +backend storage. If the device backend storage splits the request into +sub-requests, each sub-request MUST begin at a byte offset, from the start +of \field{data}, that is a multiple of $(1 << \field{data_unit_size_bits})$ +bytes, MUST have a length that is a multiple of +$(1 << \field{data_unit_size_bits})$ bytes, and MUST use, in place of +\field{dun}, the Data Unit Number +$\field{dun} + (\mathit{byte\_offset} / (1 << \field{data_unit_size_bits}))$, +where $\mathit{byte\_offset}$ is that sub-request's starting byte offset +from the start of \field{data}. + \subsubsection{Legacy Interface: Device Operation}\label{sec:Device Types / Block Device / Device Operation / Legacy Interface: Device Operation} When using the legacy interface, transitional devices and drivers MUST format the fields in struct virtio_blk_req -- 2.34.1