virt: sevguest: Add support to derive key
authorBrijesh Singh <brijesh.singh@amd.com>
Thu, 24 Feb 2022 16:56:23 +0000 (10:56 -0600)
committerBorislav Petkov <bp@suse.de>
Thu, 7 Apr 2022 14:47:12 +0000 (16:47 +0200)
The SNP_GET_DERIVED_KEY ioctl interface can be used by the SNP guest to
ask the firmware to provide a key derived from a root key. The derived
key may be used by the guest for any purposes it chooses, such as a
sealing key or communicating with the external entities.

See SEV-SNP firmware spec for more information.

  [ bp: No need to memset "req" - it will get overwritten. ]

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
Link: https://lore.kernel.org/r/20220307213356.2797205-45-brijesh.singh@amd.com
Documentation/virt/coco/sevguest.rst
drivers/virt/coco/sevguest/sevguest.c
include/uapi/linux/sev-guest.h

index 3da782e867a3d92515350c91bf87a5ca572b1b6b..4135c14312411a540b7257f25e73ee818e7c1dec 100644 (file)
@@ -77,6 +77,23 @@ On success, the snp_report_resp.data will contains the report. The report
 contain the format described in the SEV-SNP specification. See the SEV-SNP
 specification for further details.
 
+2.2 SNP_GET_DERIVED_KEY
+-----------------------
+:Technology: sev-snp
+:Type: guest ioctl
+:Parameters (in): struct snp_derived_key_req
+:Returns (out): struct snp_derived_key_resp on success, -negative on error
+
+The SNP_GET_DERIVED_KEY ioctl can be used to get a key derive from a root key.
+The derived key can be used by the guest for any purpose, such as sealing keys
+or communicating with external entities.
+
+The ioctl uses the SNP_GUEST_REQUEST (MSG_KEY_REQ) command provided by the
+SEV-SNP firmware to derive the key. See SEV-SNP specification for further details
+on the various fields passed in the key derivation request.
+
+On success, the snp_derived_key_resp.data contains the derived key value. See
+the SEV-SNP specification for further details.
 
 Reference
 ---------
index beda93cdeb4f50c654a4e198fcd2ce4c253665fd..393777b72e5eb9af14fa9126d3681b8fbc3d4b6a 100644 (file)
@@ -391,6 +391,48 @@ e_free:
        return rc;
 }
 
+static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
+{
+       struct snp_guest_crypto *crypto = snp_dev->crypto;
+       struct snp_derived_key_resp resp = {0};
+       struct snp_derived_key_req req;
+       int rc, resp_len;
+       /* Response data is 64 bytes and max authsize for GCM is 16 bytes. */
+       u8 buf[64 + 16];
+
+       lockdep_assert_held(&snp_cmd_mutex);
+
+       if (!arg->req_data || !arg->resp_data)
+               return -EINVAL;
+
+       /*
+        * The intermediate response buffer is used while decrypting the
+        * response payload. Make sure that it has enough space to cover the
+        * authtag.
+        */
+       resp_len = sizeof(resp.data) + crypto->a_len;
+       if (sizeof(buf) < resp_len)
+               return -ENOMEM;
+
+       if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req)))
+               return -EFAULT;
+
+       rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg->msg_version,
+                                 SNP_MSG_KEY_REQ, &req, sizeof(req), buf, resp_len,
+                                 &arg->fw_err);
+       if (rc)
+               return rc;
+
+       memcpy(resp.data, buf, sizeof(resp.data));
+       if (copy_to_user((void __user *)arg->resp_data, &resp, sizeof(resp)))
+               rc = -EFAULT;
+
+       /* The response buffer contains the sensitive data, explicitly clear it. */
+       memzero_explicit(buf, sizeof(buf));
+       memzero_explicit(&resp, sizeof(resp));
+       return rc;
+}
+
 static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
 {
        struct snp_guest_dev *snp_dev = to_snp_dev(file);
@@ -420,6 +462,9 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long
        case SNP_GET_REPORT:
                ret = get_report(snp_dev, &input);
                break;
+       case SNP_GET_DERIVED_KEY:
+               ret = get_derived_key(snp_dev, &input);
+               break;
        default:
                break;
        }
index 38f11d723c6871dc8b01d06bff2874d2a725b708..598367f12064376487edd77a38c84836e9ea615e 100644 (file)
@@ -30,6 +30,20 @@ struct snp_report_resp {
        __u8 data[4000];
 };
 
+struct snp_derived_key_req {
+       __u32 root_key_select;
+       __u32 rsvd;
+       __u64 guest_field_select;
+       __u32 vmpl;
+       __u32 guest_svn;
+       __u64 tcb_version;
+};
+
+struct snp_derived_key_resp {
+       /* response data, see SEV-SNP spec for the format */
+       __u8 data[64];
+};
+
 struct snp_guest_request_ioctl {
        /* message version number (must be non-zero) */
        __u8 msg_version;
@@ -47,4 +61,7 @@ struct snp_guest_request_ioctl {
 /* Get SNP attestation report */
 #define SNP_GET_REPORT _IOWR(SNP_GUEST_REQ_IOC_TYPE, 0x0, struct snp_guest_request_ioctl)
 
+/* Get a derived key from the root */
+#define SNP_GET_DERIVED_KEY _IOWR(SNP_GUEST_REQ_IOC_TYPE, 0x1, struct snp_guest_request_ioctl)
+
 #endif /* __UAPI_LINUX_SEV_GUEST_H_ */