Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/sbellem/sgx-bsm

Black-Scholes-Merton computation in Intel SGX (PROTOTYPE)
https://github.com/sbellem/sgx-bsm

Last synced: 3 days ago
JSON representation

Black-Scholes-Merton computation in Intel SGX (PROTOTYPE)

Awesome Lists containing this project

README

        

# Black-Scholes-Merton Computation in Intel SGX
**Prototype** to demonstrate a computation based on the
[Black-Scholes-Merton](https://brilliant.org/wiki/black-scholes-merton/) mathematical
model.

**This is work-in-progress.**

The SGX specific source code is based on [sgx-iot](https://github.com/sbellem/sgx-iot),
which is itself an adaptation of [Key Provisioning, Secure Signing, and Verifiable
Remote Attestation using Intel® SGX](https://software.intel.com/content/www/us/en/develop/articles/code-sample-gateway-key-provisioning-and-secure-signing-using-intel-software-guard.html)

The focus of this adaptation is on combining the key generation with remote
attestation such that the public key is included in the report data of a remote
attestation report. Moreover the code samples demonstrate how the remote attestation
verification report can be used to verify the reported MRENCLAVE against the trusted
source code, using a docker & nix -based toolchain, managed by a small tool named
[`auditee`](https://auditee.readthedocs.io).

## Prerequisites
* You need [docker](https://docs.docker.com/engine/install/) (version 19.03+) and
[docker-compose](https://docs.docker.com/compose/install/).

* The docker-based development environment assumes it is running on an SGX-enabled
processor. If you are not sure whether your computer supports SGX, and/or how to
enable it, see https://github.com/ayeks/SGX-hardware#test-sgx.

* Obtain an **Unlinkable** subscription key for the
[Intel SGX Attestation Service Utilizing Enhanced Privacy ID (EPID)](https://api.portal.trustedservices.intel.com/).

## Quickstart

### Set Environment Variables
Before starting a container, set the two following environment variables:

* `SGX_SPID` - used to create a quote
* `IAS_PRIMARY_KEY` - used to access Intel's Attestation Service (IAS)

```shell
export SGX_SPID=
export IAS_PRIMARY_KEY=
```

Alternatively, you can use place the environment variables in a `.env` file, under
the root of the repository. **NOTE** that the `IAS_PRIMARY_KEY` **MUST** be kept
secret. Consequently, the file `.env` is not tracked by git, as it **MUST NOT** be
uploaded to a public repository, such as on GitHub.

```shell
# .env sample
SGX_SPID=
IAS_PRIMARY_KEY=
```

### Run the demo
The demo creates an asymmetric elliptic curve keypair. It seals both the private key and
public key. The public key is sealed to protect it against tampering as it is included
in the attestation report from which a quote is generated, and can be verified by
sending it to Intel's Attestation Service. Upon a successful verification of the
quote, the client checks that the MRENCLAVE contained in the reoprt matches that of
the trusted source code. That is, when re-building the enclave from source, its
MRENCLAVE is the trusted reference. If the MRENCLAVE matches the client extracts
the public key out of the report data, and uses that public key to verify the signature
generated by the enclave. If the signature is valid, the client can trust the sensor
data.

```shell
$ docker-compose run --rm sgxbsm ./run_demo_sgxra.sh
```

```console
...
...
...

Reproducibility Report
----------------------
- Signed enclave MRENCLAVE: ef5999651f24e3258222db2f25aab8b5ac23e7b2dce92ea270285f26cde117f1
- Built-from-source enclave MRENCLAVE: ef5999651f24e3258222db2f25aab8b5ac23e7b2dce92ea270285f26cde117f1
- IAS report MRENCLAVE: ef5999651f24e3258222db2f25aab8b5ac23e7b2dce92ea270285f26cde117f1

MRENCLAVES match!

Report data
-----------
The following REPORT DATA contained in the remote attestation verification report CAN be trusted.
81d431d2bb1e11c5dc820be35f1770d05df0e88aeb815998f213bbb251c10f7d6def5a62627c79afbe754c81b15e9f1f01b6d3e86e9e098ae1e3d3d2f90be9cf

Extracting public key from IAS report ...
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfQ/BUbK7E/KYWYHriujwXdBwF1/j
C4LcxREeu9Ix1IHP6Qv50tPj4YoJnm7o07YBH59esYFMdb6veXxiYlrvbQ==
-----END PUBLIC KEY-----

Verifying signature:
30450220480a985da227c17351aca13c086b947ebcd9404e9fc241121a5157036e38b15d022100ad4f45c9f42f53f7ac70347bb2217f3307ff74578155500e2fe9f298a7654f15

for Black-Scholes-Merton computation result:
82.51920537868105

Signature verification successful!
```

The sections below, provide some details about some key steps of the demo.

### Send the quote to Intel
**WARNING: Example below is outdated. Will be updated soon.**

Go into an ipython shell:

```shell
ipython
```

Copy the quote from the output, and assign it to a variable:

```python
quote = {
"isvEnclaveQuote":"AgAAAFsLAAALAAoAAAAAAFOrdeScwC/lZP1RWReIG+iRaFn0HiQK7vu+7g8BckAuCRH//wECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAHAAAAAAAAAKijCU12IXxd0KESasFCs23TT4hRSpm/jfyOqFLx+mI4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnBOOv77LJPGq5rW5P2XqTpdBWpBwqmccBzKH18B98SwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0gEAU6MLnODQoKJlw5fZz7sUJYj5Z6qx78ar7B4V4pEKKhfhEyl/krjOiPlIzno5hNeorr3jOEnuUOs6l2kboqAIAAHmlFCVS6cp4FM7WhB3jpxWVDukXLMRgBvaHshb1qfuRqR6twO+shb5XQkLd/bNftWeTtZC+IVyUWjqSFJhuMyt8lXiNureQxoTxHvTa2//lL0tMKGjgZBt01ucRhIeyIb9LnAvgLw7EXuRmit4RjRKfVpSgMjnYtu1ZDsO+qoSCGlfY2WDy4oHCBQvz/ErTGA4cX20luT3G+4V9rvbUFL1XcdrRzEIBeOYv1o3w3ZhmhLNrqBxlB8JJrndMTvRb+idI5CYK7AGGIMvO6XPzgzDKvm2T+4hpqwQrUoQQilvcIkAJ7els/y53psv/m/T6R07ygBGkSF0kHFgnP1o7gs510cI7E7s714smfwnf7+fQMmDIIqBuOUCcAwmVMTbkpYETLGZwfMaaCI2tvWgBAADt2TDVlkTLaf/Hi5xnk8NaA/PcdbEVNf1LGnuorB4qY5dvM83rF6ABEV7N6uF5pH73b/oZwY+F4AxJW1cb8zjSrGJVb+LlO2zOrtDs0mb1RfckXChrGEgZtj0Tx584YSDRhPuQp2mvQjQyVYrOGCfzhyIDyiuqbhbvjPXWVVVKIjBWh+QZxZ3b/YJBPm38/XQfWV/JotJUMB6rUUzGSZi91a/Eb/7hrNjRyKXAYboog4IHrKJWgLRwPSdNcjZAeZAjZKJK5OCEk25341G6FoG34H9k6LeXidTBk/VRXrzlBbbbBbLg8mMqGDLv0WVXZnaYgDf/Jidu8vp08vknfi28PtxcIWmqwXOazO00yHU7OvUfjynnOxh0t+REa2YYxdehPAfO0nsgVmUruuj3s2vwtbgiQ6il03O/Sw4CabOya3C8Evce6tTHoPBtYGVs24Tgn5mXM+NSRs+ad+eDKsSqHymzd/sVrYaJlmL87zlcvtC8y33FVEIJ"
}
```

To send the quote over to Intel, you need your API primary subscription key,
which you should have set as an environment variable before starting the
container. (See the prerequisite section if needed.)

```python
import os

headers = {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': os.environ["IAS_PRIMARY_KEY"],
}
```

send the quote for verification:

```python
import requests

url = 'https://api.trustedservices.intel.com/sgx/dev/attestation/v4/report'

res = requests.post(url, json=quote, headers=headers)
```

If everything went well the `res.status_code` should be 200, or
`res.ok` `True`. You can look at `res.reason` for more information if you
got an error.

```python
In [6]: res.json()
Out[6]:
{'id': '241352371682676293259277452268094264738',
'timestamp': '2021-05-20T04:51:10.638041',
'version': 4,
'advisoryURL': 'https://security-center.intel.com',
'advisoryIDs': ['INTEL-SA-00161',
'INTEL-SA-00381',
'INTEL-SA-00389',
'INTEL-SA-00320',
'INTEL-SA-00329',
'INTEL-SA-00220',
'INTEL-SA-00270',
'INTEL-SA-00293'],
'isvEnclaveQuoteStatus': 'GROUP_OUT_OF_DATE',
'platformInfoBlob': '150200650400090000111102040101070000000000000000000B00000B000000020000000000000B5B6DB2D012D7BBA9067D6818A3CCBDEDC2EA2250EF57A18F3F85B03FAA9A09E606FE0414651A88C4F5335A733BC0C521083D62358CD310BD088C9C62A07B29E9F5',
'isvEnclaveQuoteBody': 'AgAAAFsLAAALAAoAAAAAAFOrdeScwC/lZP1RWReIG+iRaFn0HiQK7vu+7g8BckAuCRH//wECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAHAAAAAAAAAKijCU12IXxd0KESasFCs23TT4hRSpm/jfyOqFLx+mI4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnBOOv77LJPGq5rW5P2XqTpdBWpBwqmccBzKH18B98SwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0gEAU6MLnODQoKJlw5fZz7sUJYj5Z6qx78ar7B4V4pEKKhfhEyl/krjOiPlIzno5hNeorr3jOEnuUOs6l2kbo'}
```

With the above output, it's possible to check the MRENCLAVE, etc, and to
extract the public key out of the report data.

**NOTE:** The `res.headers` are important to check signature and certificates
to make sure the report is authentic, meaning that it was signed by Intel's
key.

### Verify the MRENCLAVE
**TODO**

### Extract the Public Key
From the json of the response, we get the quote body, encoded in base 64.

```python
quote_body = res.json()['isvEnclaveQuoteBody']
```

In order to extract the report data out of the quote, it's necessary to be
aware of the structure of a quote (`sgx_quote_t`) and of a report
(`sgx_report_body_t`).

```C
typedef struct _quote_t
{
uint16_t version; /* 0 */
uint16_t sign_type; /* 2 */
sgx_epid_group_id_t epid_group_id; /* 4 */
sgx_isv_svn_t qe_svn; /* 8 */
sgx_isv_svn_t pce_svn; /* 10 */
uint32_t xeid; /* 12 */
sgx_basename_t basename; /* 16 */
sgx_report_body_t report_body; /* 48 */
uint32_t signature_len; /* 432 */
uint8_t signature[]; /* 436 */
} sgx_quote_t;
```

The repport data is at the end of the `report_body`, at offset 320:

```C
typedef struct _report_body_t
{
sgx_cpu_svn_t cpu_svn; /* ( 0) Security Version of the CPU */
sgx_misc_select_t misc_select; /* ( 16) Which fields defined in SSA.MISC */
uint8_t reserved1[SGX_REPORT_BODY_RESERVED1_BYTES]; /* ( 20) */
sgx_isvext_prod_id_t isv_ext_prod_id;/* ( 32) ISV assigned Extended Product ID */
sgx_attributes_t attributes; /* ( 48) Any special Capabilities the Enclave possess */
sgx_measurement_t mr_enclave; /* ( 64) The value of the enclave's ENCLAVE measurement */
uint8_t reserved2[SGX_REPORT_BODY_RESERVED2_BYTES]; /* ( 96) */
sgx_measurement_t mr_signer; /* (128) The value of the enclave's SIGNER measurement */
uint8_t reserved3[SGX_REPORT_BODY_RESERVED3_BYTES]; /* (160) */
sgx_config_id_t config_id; /* (192) CONFIGID */
sgx_prod_id_t isv_prod_id; /* (256) Product ID of the Enclave */
sgx_isv_svn_t isv_svn; /* (258) Security Version of the Enclave */
sgx_config_svn_t config_svn; /* (260) CONFIGSVN */
uint8_t reserved4[SGX_REPORT_BODY_RESERVED4_BYTES]; /* (262) */
sgx_isvfamily_id_t isv_family_id; /* (304) ISV assigned Family ID */
sgx_report_data_t report_data; /* (320) Data provided by the user */
} sgx_report_body_t;
```

With the above information, we can decode the base 64 encoded quote, and
access the report data in it.

```python
import base64

report_data = base64.b64decode(quote_body)[368:432]
```

The original demo wrote the public key in PEM format under the file
`demo_sgx/secp256r1.pem`. The public key we have in the report data should
match the one in the `.pem` file. We'll use Python's `cryptography` library to
verify this.

With Python's `cryptography` library, the public point can be used to
instantiate a public key object, `EllipticCurvePublicKey`, from which it's
possible to obtain other formats such as PEM and DER.

It's important to note that Python's cryptography library expects the point to
be encoded as per Section 2.3.3 in https://www.secg.org/sec1-v2.pdf. The
report data contains both x and y coordinates, in uncompressed form, and
without the octet prefix `04`. It's therefore necessary to add the octet
prefix to the report data.

```python
from cryptography.hazmat.primitives.asymmetric import ec

point = b"\x04" + report_data
pubkey = ec.EllipticCurvePublicKey.from_encoded_point(curve=ec.SECP256R1(), data=point)
```

Check that it matches the PEM data file:

```python
from cryptography.hazmat.primitives import serialization

pem_from_report_data = pubkey.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)

with open('demo_sgx/secp256r1.pem') as f:
pem_file_data = f.read()

pem_from_report_data == pem_file_data.encode()
# True
```

### Verify the Signed Data
```python
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec

with open('demo_sgx/bsm_result.sig', 'rb') as f:
signature = f.read()

with open('demo_sgx/bsm_result.out', 'rb') as f:
bsm_result = f.read()

pubkey.verify(
signature,
bsm_result,
signature_algorithm=ec.ECDSA(hashes.SHA256()),
)
```