Re: [PATCH] KVM/SVM: add support for SEV attestation command

2020-12-13 Thread James Bottomley
On Wed, 2020-12-09 at 21:25 -0600, Brijesh Singh wrote:
> Noted, I will send v2 with these fixed.

I ran a test on this.  It turns out for rome systems you need firmware
md_sev_fam17h_model3xh_0.24b0A (or later) installed to get this and the
QEMU patch with the base64 decoding fixed, but with that

Tested-by: James Bottomley 

Attached is the test programme I used.

James

---

#!/usr/bin/python3
##
# Python script get an attestation and verify it with the PEK
#
# This assumes you've already exported the pek.cert with sev-tool
# from https://github.com/AMDESE/sev-tool.git
#
# sev-tool --export_cert_chain
#
# creates several files, the only one this script needs is pek.cert
#
# Tables and chapters refer to the amd 55766.pdf document
#
# https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf
##
import sys
import os 
import base64
import hashlib
from argparse import ArgumentParser
from Crypto.PublicKey import ECC
from Crypto.Math.Numbers import Integer
from git.qemu.python.qemu import qmp

if __name__ == "__main__":
parser = ArgumentParser(description='Inject secret into SEV')
parser.add_argument('--pek-cert',
help='The Platform DH certificate in binary form',
default='pek.cert')
parser.add_argument('--socket',
help='Socket to connect to QMP on, defaults to 
localhost:6550',
default='localhost:6550')
args = parser.parse_args()

if (args.socket[0] == '/'):
socket = args.socket
elif (':' in args.socket):
s = args.socket.split(':')
socket = (s[0], int(s[1]))
else:
parse.error('--socket must be : or /path/to/unix')

fh = open(args.pek_cert, 'rb')
pek = bytearray(fh.read())
curve = int.from_bytes(pek[16:20], byteorder='little')
curves = {
1: 'p256',
2: 'p384'
}
Qx = int.from_bytes(bytes(pek[20:92]), byteorder='little')
Qy = int.from_bytes(bytes(pek[92:164]), byteorder='little')

pubkey = ECC.construct(point_x=Qx, point_y=Qy, curve=curves[curve])

Qmp = qmp.QEMUMonitorProtocol(address=socket);
Qmp.connect()
caps = Qmp.command('query-sev')
print('SEV query found API={api-major}.{api-minor} build={build-id} 
policy={policy}\n'.format(**caps))

nonce=os.urandom(16)

report = Qmp.command('query-sev-attestation-report',
 mnonce=base64.b64encode(nonce).decode())

a = base64.b64decode(report['data'])

##
# returned data is formulated as Table 60. Attestation Report Buffer
##
rnonce = a[0:16]
rmeas = a[16:48]

if (nonce != rnonce):
sys.exit('returned nonce doesn\'t match input nonce')

policy = int.from_bytes(a[48:52], byteorder='little')
usage = int.from_bytes(a[52:56], byteorder='little')
algo = int.from_bytes(a[56:60], byteorder='little')

if (policy != caps['policy']):
sys.exit('Policy mismatch:', policy, '!=', caps['policy'])

if (usage != 0x1002):
sys.exit('error PEK is not specified in usage: ', usage)

if (algo == 0x2):
h = hashlib.sha256()
elif (algo == 0x102):
##
# The spec (6.8) says the signature must be ECDSA-SHA256 so this
# should be impossible, but it turns out to be the way our
# current test hardware produces its signature
##
h = hashlib.sha384()
else:
sys.exit('unrecognized signing algorithm: ', algo)

h.update(a[0:52])

sig = a[64:208]
r = int.from_bytes(sig[0:72],byteorder='little')
s = int.from_bytes(sig[72:144],byteorder='little')
##
# subtlety: r and s are little (AMD defined) z is big (crypto requirement)
##
z = int.from_bytes(h.digest(), byteorder='big')

##
# python crypto doesn't have a way of passing in r and s as
# integers and I'm not inclined to wrap them up as a big endian
# binary signature to have Signature.DSS unwrap them again, so
# call the _verify() private interface that does take integers
##
if (not pubkey._verify(Integer(z), (Integer(r), Integer(s:
sys.exit('returned signature did not verify')

print('usage={usage}, algorithm={algo}'.format(usage=hex(usage),
   algo=hex(algo)))
print('ovmf-hash: ', rmeas.hex())



Re: [PATCH] KVM/SVM: add support for SEV attestation command

2020-12-10 Thread David Rientjes
On Wed, 9 Dec 2020, Brijesh Singh wrote:

> Noted, I will send v2 with these fixed.
> 

And with those changes:

Acked-by: David Rientjes 

Thanks Brijesh!


Re: [PATCH] KVM/SVM: add support for SEV attestation command

2020-12-09 Thread Brijesh Singh


On 12/9/20 1:51 AM, Ard Biesheuvel wrote:
> On Fri, 4 Dec 2020 at 22:30, Brijesh Singh  wrote:
>> The SEV FW version >= 0.23 added a new command that can be used to query
>> the attestation report containing the SHA-256 digest of the guest memory
>> encrypted through the KVM_SEV_LAUNCH_UPDATE_{DATA, VMSA} commands and
>> sign the report with the Platform Endorsement Key (PEK).
>>
>> See the SEV FW API spec section 6.8 for more details.
>>
>> Note there already exist a command (KVM_SEV_LAUNCH_MEASURE) that can be
>> used to get the SHA-256 digest. The main difference between the
>> KVM_SEV_LAUNCH_MEASURE and KVM_SEV_ATTESTATION_REPORT is that the later
> latter
>
>> can be called while the guest is running and the measurement value is
>> signed with PEK.
>>
>> Cc: James Bottomley 
>> Cc: Tom Lendacky 
>> Cc: David Rientjes 
>> Cc: Paolo Bonzini 
>> Cc: Sean Christopherson 
>> Cc: Borislav Petkov 
>> Cc: John Allen 
>> Cc: Herbert Xu 
>> Cc: linux-cry...@vger.kernel.org
>> Signed-off-by: Brijesh Singh 
>> ---
>>  .../virt/kvm/amd-memory-encryption.rst| 21 ++
>>  arch/x86/kvm/svm/sev.c| 71 +++
>>  drivers/crypto/ccp/sev-dev.c  |  1 +
>>  include/linux/psp-sev.h   | 17 +
>>  include/uapi/linux/kvm.h  |  8 +++
>>  5 files changed, 118 insertions(+)
>>
>> diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst 
>> b/Documentation/virt/kvm/amd-memory-encryption.rst
>> index 09a8f2a34e39..4c6685d0fddd 100644
>> --- a/Documentation/virt/kvm/amd-memory-encryption.rst
>> +++ b/Documentation/virt/kvm/amd-memory-encryption.rst
>> @@ -263,6 +263,27 @@ Returns: 0 on success, -negative on error
>>  __u32 trans_len;
>>  };
>>
>> +10. KVM_SEV_GET_ATTESATION_REPORT
> KVM_SEV_GET_ATTESTATION_REPORT
>
>> +-
>> +
>> +The KVM_SEV_GET_ATTESATION_REPORT command can be used by the hypervisor to 
>> query the attestation
> KVM_SEV_GET_ATTESTATION_REPORT


Noted, I will send v2 with these fixed.



Re: [PATCH] KVM/SVM: add support for SEV attestation command

2020-12-08 Thread Ard Biesheuvel
On Fri, 4 Dec 2020 at 22:30, Brijesh Singh  wrote:
>
> The SEV FW version >= 0.23 added a new command that can be used to query
> the attestation report containing the SHA-256 digest of the guest memory
> encrypted through the KVM_SEV_LAUNCH_UPDATE_{DATA, VMSA} commands and
> sign the report with the Platform Endorsement Key (PEK).
>
> See the SEV FW API spec section 6.8 for more details.
>
> Note there already exist a command (KVM_SEV_LAUNCH_MEASURE) that can be
> used to get the SHA-256 digest. The main difference between the
> KVM_SEV_LAUNCH_MEASURE and KVM_SEV_ATTESTATION_REPORT is that the later

latter

> can be called while the guest is running and the measurement value is
> signed with PEK.
>
> Cc: James Bottomley 
> Cc: Tom Lendacky 
> Cc: David Rientjes 
> Cc: Paolo Bonzini 
> Cc: Sean Christopherson 
> Cc: Borislav Petkov 
> Cc: John Allen 
> Cc: Herbert Xu 
> Cc: linux-cry...@vger.kernel.org
> Signed-off-by: Brijesh Singh 
> ---
>  .../virt/kvm/amd-memory-encryption.rst| 21 ++
>  arch/x86/kvm/svm/sev.c| 71 +++
>  drivers/crypto/ccp/sev-dev.c  |  1 +
>  include/linux/psp-sev.h   | 17 +
>  include/uapi/linux/kvm.h  |  8 +++
>  5 files changed, 118 insertions(+)
>
> diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst 
> b/Documentation/virt/kvm/amd-memory-encryption.rst
> index 09a8f2a34e39..4c6685d0fddd 100644
> --- a/Documentation/virt/kvm/amd-memory-encryption.rst
> +++ b/Documentation/virt/kvm/amd-memory-encryption.rst
> @@ -263,6 +263,27 @@ Returns: 0 on success, -negative on error
>  __u32 trans_len;
>  };
>
> +10. KVM_SEV_GET_ATTESATION_REPORT

KVM_SEV_GET_ATTESTATION_REPORT

> +-
> +
> +The KVM_SEV_GET_ATTESATION_REPORT command can be used by the hypervisor to 
> query the attestation

KVM_SEV_GET_ATTESTATION_REPORT

> +report containing the SHA-256 digest of the guest memory and VMSA passed 
> through the KVM_SEV_LAUNCH
> +commands and signed with the PEK. The digest returned by the command should 
> match the digest
> +used by the guest owner with the KVM_SEV_LAUNCH_MEASURE.
> +
> +Parameters (in): struct kvm_sev_attestation
> +
> +Returns: 0 on success, -negative on error
> +
> +::
> +
> +struct kvm_sev_attestation_report {
> +__u8 mnonce[16];/* A random mnonce that will be 
> placed in the report */
> +
> +__u64 uaddr;/* userspace address where the 
> report should be copied */
> +__u32 len;
> +};
> +
>  References
>  ==
>
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index 566f4d18185b..c4d3ee6be362 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -927,6 +927,74 @@ static int sev_launch_secret(struct kvm *kvm, struct 
> kvm_sev_cmd *argp)
> return ret;
>  }
>
> +static int sev_get_attestation_report(struct kvm *kvm, struct kvm_sev_cmd 
> *argp)
> +{
> +   void __user *report = (void __user *)(uintptr_t)argp->data;
> +   struct kvm_sev_info *sev = _kvm_svm(kvm)->sev_info;
> +   struct sev_data_attestation_report *data;
> +   struct kvm_sev_attestation_report params;
> +   void __user *p;
> +   void *blob = NULL;
> +   int ret;
> +
> +   if (!sev_guest(kvm))
> +   return -ENOTTY;
> +
> +   if (copy_from_user(, (void __user *)(uintptr_t)argp->data, 
> sizeof(params)))
> +   return -EFAULT;
> +
> +   data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> +   if (!data)
> +   return -ENOMEM;
> +
> +   /* User wants to query the blob length */
> +   if (!params.len)
> +   goto cmd;
> +
> +   p = (void __user *)(uintptr_t)params.uaddr;
> +   if (p) {
> +   if (params.len > SEV_FW_BLOB_MAX_SIZE) {
> +   ret = -EINVAL;
> +   goto e_free;
> +   }
> +
> +   ret = -ENOMEM;
> +   blob = kmalloc(params.len, GFP_KERNEL);
> +   if (!blob)
> +   goto e_free;
> +
> +   data->address = __psp_pa(blob);
> +   data->len = params.len;
> +   memcpy(data->mnonce, params.mnonce, sizeof(params.mnonce));
> +   }
> +cmd:
> +   data->handle = sev->handle;
> +   ret = sev_issue_cmd(kvm, SEV_CMD_ATTESTATION_REPORT, data, 
> >error);
> +   /*
> +* If we query the session length, FW responded with expected data.
> +*/
> +   if (!params.len)
> +   goto done;
> +
> +   if (ret)
> +   goto e_free_blob;
> +
> +   if (blob) {
> +   if (copy_to_user(p, blob, params.len))
> +   ret = -EFAULT;
> +   }
> +
> +done:
> +   params.len = data->len;
> +   if (copy_to_user(report, , sizeof(params)))
> +   ret = -EFAULT;
> +e_free_blob:
> 

Re: [PATCH] KVM/SVM: add support for SEV attestation command

2020-12-08 Thread Tom Lendacky
On 12/4/20 3:28 PM, Brijesh Singh wrote:
> The SEV FW version >= 0.23 added a new command that can be used to query
> the attestation report containing the SHA-256 digest of the guest memory
> encrypted through the KVM_SEV_LAUNCH_UPDATE_{DATA, VMSA} commands and
> sign the report with the Platform Endorsement Key (PEK).
> 
> See the SEV FW API spec section 6.8 for more details.
> 
> Note there already exist a command (KVM_SEV_LAUNCH_MEASURE) that can be
> used to get the SHA-256 digest. The main difference between the
> KVM_SEV_LAUNCH_MEASURE and KVM_SEV_ATTESTATION_REPORT is that the later
> can be called while the guest is running and the measurement value is
> signed with PEK.
> 
> Cc: James Bottomley 
> Cc: Tom Lendacky 
> Cc: David Rientjes 
> Cc: Paolo Bonzini 
> Cc: Sean Christopherson 
> Cc: Borislav Petkov 
> Cc: John Allen 
> Cc: Herbert Xu 
> Cc: linux-cry...@vger.kernel.org
> Signed-off-by: Brijesh Singh 

Reviewed-by: Tom Lendacky 

Not sure if Paolo or Herbert would like the crypto/psp changes to be split
out from the kvm changes as separate patches or not.

Thanks,
Tom

> ---
>  .../virt/kvm/amd-memory-encryption.rst| 21 ++
>  arch/x86/kvm/svm/sev.c| 71 +++
>  drivers/crypto/ccp/sev-dev.c  |  1 +
>  include/linux/psp-sev.h   | 17 +
>  include/uapi/linux/kvm.h  |  8 +++
>  5 files changed, 118 insertions(+)
> 
> diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst 
> b/Documentation/virt/kvm/amd-memory-encryption.rst
> index 09a8f2a34e39..4c6685d0fddd 100644
> --- a/Documentation/virt/kvm/amd-memory-encryption.rst
> +++ b/Documentation/virt/kvm/amd-memory-encryption.rst
> @@ -263,6 +263,27 @@ Returns: 0 on success, -negative on error
>  __u32 trans_len;
>  };
>  
> +10. KVM_SEV_GET_ATTESATION_REPORT
> +-
> +
> +The KVM_SEV_GET_ATTESATION_REPORT command can be used by the hypervisor to 
> query the attestation
> +report containing the SHA-256 digest of the guest memory and VMSA passed 
> through the KVM_SEV_LAUNCH
> +commands and signed with the PEK. The digest returned by the command should 
> match the digest
> +used by the guest owner with the KVM_SEV_LAUNCH_MEASURE.
> +
> +Parameters (in): struct kvm_sev_attestation
> +
> +Returns: 0 on success, -negative on error
> +
> +::
> +
> +struct kvm_sev_attestation_report {
> +__u8 mnonce[16];/* A random mnonce that will be 
> placed in the report */
> +
> +__u64 uaddr;/* userspace address where the 
> report should be copied */
> +__u32 len;
> +};
> +
>  References
>  ==
>  
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index 566f4d18185b..c4d3ee6be362 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -927,6 +927,74 @@ static int sev_launch_secret(struct kvm *kvm, struct 
> kvm_sev_cmd *argp)
>   return ret;
>  }
>  
> +static int sev_get_attestation_report(struct kvm *kvm, struct kvm_sev_cmd 
> *argp)
> +{
> + void __user *report = (void __user *)(uintptr_t)argp->data;
> + struct kvm_sev_info *sev = _kvm_svm(kvm)->sev_info;
> + struct sev_data_attestation_report *data;
> + struct kvm_sev_attestation_report params;
> + void __user *p;
> + void *blob = NULL;
> + int ret;
> +
> + if (!sev_guest(kvm))
> + return -ENOTTY;
> +
> + if (copy_from_user(, (void __user *)(uintptr_t)argp->data, 
> sizeof(params)))
> + return -EFAULT;
> +
> + data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
> + if (!data)
> + return -ENOMEM;
> +
> + /* User wants to query the blob length */
> + if (!params.len)
> + goto cmd;
> +
> + p = (void __user *)(uintptr_t)params.uaddr;
> + if (p) {
> + if (params.len > SEV_FW_BLOB_MAX_SIZE) {
> + ret = -EINVAL;
> + goto e_free;
> + }
> +
> + ret = -ENOMEM;
> + blob = kmalloc(params.len, GFP_KERNEL);
> + if (!blob)
> + goto e_free;
> +
> + data->address = __psp_pa(blob);
> + data->len = params.len;
> + memcpy(data->mnonce, params.mnonce, sizeof(params.mnonce));
> + }
> +cmd:
> + data->handle = sev->handle;
> + ret = sev_issue_cmd(kvm, SEV_CMD_ATTESTATION_REPORT, data, 
> >error);
> + /*
> +  * If we query the session length, FW responded with expected data.
> +  */
> + if (!params.len)
> + goto done;
> +
> + if (ret)
> + goto e_free_blob;
> +
> + if (blob) {
> + if (copy_to_user(p, blob, params.len))
> + ret = -EFAULT;
> + }
> +
> +done:
> + params.len = data->len;
> + if (copy_to_user(report, , sizeof(params)))
> + ret = -EFAULT;
> +e_free_blob:
> + 

[PATCH] KVM/SVM: add support for SEV attestation command

2020-12-04 Thread Brijesh Singh
The SEV FW version >= 0.23 added a new command that can be used to query
the attestation report containing the SHA-256 digest of the guest memory
encrypted through the KVM_SEV_LAUNCH_UPDATE_{DATA, VMSA} commands and
sign the report with the Platform Endorsement Key (PEK).

See the SEV FW API spec section 6.8 for more details.

Note there already exist a command (KVM_SEV_LAUNCH_MEASURE) that can be
used to get the SHA-256 digest. The main difference between the
KVM_SEV_LAUNCH_MEASURE and KVM_SEV_ATTESTATION_REPORT is that the later
can be called while the guest is running and the measurement value is
signed with PEK.

Cc: James Bottomley 
Cc: Tom Lendacky 
Cc: David Rientjes 
Cc: Paolo Bonzini 
Cc: Sean Christopherson 
Cc: Borislav Petkov 
Cc: John Allen 
Cc: Herbert Xu 
Cc: linux-cry...@vger.kernel.org
Signed-off-by: Brijesh Singh 
---
 .../virt/kvm/amd-memory-encryption.rst| 21 ++
 arch/x86/kvm/svm/sev.c| 71 +++
 drivers/crypto/ccp/sev-dev.c  |  1 +
 include/linux/psp-sev.h   | 17 +
 include/uapi/linux/kvm.h  |  8 +++
 5 files changed, 118 insertions(+)

diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst 
b/Documentation/virt/kvm/amd-memory-encryption.rst
index 09a8f2a34e39..4c6685d0fddd 100644
--- a/Documentation/virt/kvm/amd-memory-encryption.rst
+++ b/Documentation/virt/kvm/amd-memory-encryption.rst
@@ -263,6 +263,27 @@ Returns: 0 on success, -negative on error
 __u32 trans_len;
 };
 
+10. KVM_SEV_GET_ATTESATION_REPORT
+-
+
+The KVM_SEV_GET_ATTESATION_REPORT command can be used by the hypervisor to 
query the attestation
+report containing the SHA-256 digest of the guest memory and VMSA passed 
through the KVM_SEV_LAUNCH
+commands and signed with the PEK. The digest returned by the command should 
match the digest
+used by the guest owner with the KVM_SEV_LAUNCH_MEASURE.
+
+Parameters (in): struct kvm_sev_attestation
+
+Returns: 0 on success, -negative on error
+
+::
+
+struct kvm_sev_attestation_report {
+__u8 mnonce[16];/* A random mnonce that will be placed 
in the report */
+
+__u64 uaddr;/* userspace address where the report 
should be copied */
+__u32 len;
+};
+
 References
 ==
 
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 566f4d18185b..c4d3ee6be362 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -927,6 +927,74 @@ static int sev_launch_secret(struct kvm *kvm, struct 
kvm_sev_cmd *argp)
return ret;
 }
 
+static int sev_get_attestation_report(struct kvm *kvm, struct kvm_sev_cmd 
*argp)
+{
+   void __user *report = (void __user *)(uintptr_t)argp->data;
+   struct kvm_sev_info *sev = _kvm_svm(kvm)->sev_info;
+   struct sev_data_attestation_report *data;
+   struct kvm_sev_attestation_report params;
+   void __user *p;
+   void *blob = NULL;
+   int ret;
+
+   if (!sev_guest(kvm))
+   return -ENOTTY;
+
+   if (copy_from_user(, (void __user *)(uintptr_t)argp->data, 
sizeof(params)))
+   return -EFAULT;
+
+   data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+   if (!data)
+   return -ENOMEM;
+
+   /* User wants to query the blob length */
+   if (!params.len)
+   goto cmd;
+
+   p = (void __user *)(uintptr_t)params.uaddr;
+   if (p) {
+   if (params.len > SEV_FW_BLOB_MAX_SIZE) {
+   ret = -EINVAL;
+   goto e_free;
+   }
+
+   ret = -ENOMEM;
+   blob = kmalloc(params.len, GFP_KERNEL);
+   if (!blob)
+   goto e_free;
+
+   data->address = __psp_pa(blob);
+   data->len = params.len;
+   memcpy(data->mnonce, params.mnonce, sizeof(params.mnonce));
+   }
+cmd:
+   data->handle = sev->handle;
+   ret = sev_issue_cmd(kvm, SEV_CMD_ATTESTATION_REPORT, data, 
>error);
+   /*
+* If we query the session length, FW responded with expected data.
+*/
+   if (!params.len)
+   goto done;
+
+   if (ret)
+   goto e_free_blob;
+
+   if (blob) {
+   if (copy_to_user(p, blob, params.len))
+   ret = -EFAULT;
+   }
+
+done:
+   params.len = data->len;
+   if (copy_to_user(report, , sizeof(params)))
+   ret = -EFAULT;
+e_free_blob:
+   kfree(blob);
+e_free:
+   kfree(data);
+   return ret;
+}
+
 int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 {
struct kvm_sev_cmd sev_cmd;
@@ -971,6 +1039,9 @@ int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
case KVM_SEV_LAUNCH_SECRET:
r = sev_launch_secret(kvm, _cmd);
break;
+   case KVM_SEV_GET_ATTESTATION_REPORT:
+