From 1d538b71b9cdc6124de92de8a844c305eabd4d5d Mon Sep 17 00:00:00 2001 From: grydz Date: Thu, 28 Mar 2024 18:31:09 +0400 Subject: [PATCH 1/6] Fix: check status code of HTTP request for TCB info --- src/intel_sgx_ra/pccs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/intel_sgx_ra/pccs.py b/src/intel_sgx_ra/pccs.py index c460a68..4f2fb2f 100644 --- a/src/intel_sgx_ra/pccs.py +++ b/src/intel_sgx_ra/pccs.py @@ -129,6 +129,9 @@ def get_tcbinfo( timeout=30, ) + if response.status_code != HTTPStatus.OK: + raise PCCSResponseError(f"Unknown error, status code {response.status_code}") + tcb_cert, root_ca_cert, *others = [ x509.load_pem_x509_certificate(raw_cert) for raw_cert in re.findall( @@ -169,6 +172,9 @@ def get_qe_identity( url=f"{pccs_url}/sgx/certification/v4/qe/identity", timeout=30 ) + if response.status_code != HTTPStatus.OK: + raise PCCSResponseError(f"Unknown error, status code {response.status_code}") + tcb_cert, root_ca_cert, *others = [ x509.load_pem_x509_certificate(raw_cert) for raw_cert in re.findall( From 679a0738c0c698a128f63f35e6af81bdb837653e Mon Sep 17 00:00:00 2001 From: grydz Date: Thu, 28 Mar 2024 19:26:46 +0400 Subject: [PATCH 2/6] Bump python dependencies --- pyproject.toml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2064dcd..b051a76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,19 +21,19 @@ classifiers = [ ] dependencies = [ "requests>=2.31.0,<3.0.0", - "cryptography>=41.0.1,<42.0.0", - "authlib>=1.2.0,<2.0.0" + "cryptography>=42.0.5,<43.0.0", + "authlib>=1.3.0,<2.0.0" ] [project.optional-dependencies] tests = [ - "pylint>=2.17.4,<3.0.0", - "pycodestyle>=2.10.0,<3.0.0", + "black>=24.3.0,<25.0.0", + "isort>=5.13.2,<6.0.0", + "pylint>=3.1.0,<4.0.0", + "pycodestyle>=2.11.1,<3.0.0", "pydocstyle>=6.3.0,<7.0.0", - "mypy>=1.3.0,<2.0.0", - "black>=23.3.0,<24.0.0", - "isort>=5.12.0,<6.0.0", - "pytest>=7.3.2,<8.0.0", + "mypy>=1.9.0,<2.0.0", + "pytest>=8.1.1,<9.0.0", "types-requests>=2.31.0,<3.0.0" ] From 375c5da743ccfdd7ec8f6e95895678c48079ccf5 Mon Sep 17 00:00:00 2001 From: grydz Date: Thu, 28 Mar 2024 19:27:54 +0400 Subject: [PATCH 3/6] [CI] Fix: reuse workflow --- .github/workflows/CI.yml | 147 +++-------------------------------- .github/workflows/python.yml | 86 ++++++++++++++++++++ 2 files changed, 96 insertions(+), 137 deletions(-) create mode 100644 .github/workflows/python.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 1f4dc0b..7a96710 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -9,151 +9,24 @@ permissions: contents: read jobs: - linux: - runs-on: ubuntu-20.04 + python: strategy: + fail-fast: false matrix: - target: [x86_64] - python-version: ['3.8', '3.9', '3.10', '3.11'] - steps: - - uses: actions/checkout@v3 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: 'pip' # caching pip dependencies - - - name: Build wheels - uses: PyO3/maturin-action@v1 - with: - target: ${{ matrix.target }} - manylinux: manylinux2014 - container: quay.io/pypa/manylinux2014_x86_64 - args: --release --out dist -i ${{ matrix.python-version }} - sccache: 'true' - - - name: Upload wheels - uses: actions/upload-artifact@v3 - with: - name: wheels - path: dist - - - name: Install dependencies - run: | - if [ -f tests/requirements.txt ]; then pip install -r tests/requirements.txt; fi - pip install dist/*.whl - - - name: Package metadata - id: metadata - run: | - export PACKAGE_VERSION=$(pip inspect | jq -r '.installed | .[] | select(.metadata.name == "intel-sgx-ra") | .metadata.version') - echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> $GITHUB_OUTPUT - - - name: Code format with black - run: | - python -m black --check $PYTHON_SRC - - - name: Import check with isort - run: | - python -m isort --check --diff $PYTHON_SRC - - - name: Lint check with pylint - run: | - python -m pylint $PYTHON_SRC - - - name: Lint check with pycodestyle - run: | - python -m pycodestyle --max-line-length=90 --ignore=E203,W503 $PYTHON_SRC - - - name: Lint check with pydocstyle - run: | - python -m pydocstyle $PYTHON_SRC - - - name: Typecheck with MyPy - run: | - python -m mypy $PYTHON_SRC - - - name: Test with pytest - run: | - python -m pytest - - macos: - runs-on: macos-latest - strategy: - matrix: - target: [x86_64] - python-version: ['3.8', '3.9', '3.10', '3.11'] - - steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: 'pip' # caching pip dependencies - - - name: Build wheels - uses: PyO3/maturin-action@v1 - with: - target: ${{ matrix.target }} - args: --release --out dist -i ${{ matrix.python-version }} - sccache: 'true' - - - name: Upload wheels - uses: actions/upload-artifact@v3 - with: - name: wheels - path: dist - - - name: Install dependencies - run: | - if [ -f tests/requirements.txt ]; then pip install -r tests/requirements.txt; fi - pip install dist/*.whl - - - name: Package metadata - id: metadata - run: | - export PACKAGE_VERSION=$(pip inspect | jq -r '.installed | .[] | select(.metadata.name == "intel-sgx-ra") | .metadata.version') - echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> $GITHUB_OUTPUT - - - name: Code format with black - run: | - python -m black --check $PYTHON_SRC - - - name: Import check with isort - run: | - python -m isort --check --diff $PYTHON_SRC - - - name: Lint check with pylint - run: | - python -m pylint $PYTHON_SRC - - - name: Lint check with pycodestyle - run: | - python -m pycodestyle --max-line-length=90 --ignore=E203,W503 $PYTHON_SRC - - - name: Lint check with pydocstyle - run: | - python -m pydocstyle $PYTHON_SRC - - - name: Typecheck with MyPy - run: | - python -m mypy $PYTHON_SRC - - - name: Test with pytest - run: | - python -m pytest + os: [ubuntu-20.04, macos-13] + uses: ./.github/workflows/python.yml + name: Python CI (${{ matrix.os }}) + with: + os: ${{ matrix.os }} release: name: Release runs-on: ubuntu-latest if: "startsWith(github.ref, 'refs/tags/')" - needs: [linux, macos] + needs: python steps: - - uses: actions/download-artifact@v3 - with: - name: wheels + - name: Download artifacts + uses: actions/download-artifact@v4 - name: Publish to PyPI uses: PyO3/maturin-action@v1 env: diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml new file mode 100644 index 0000000..c16886f --- /dev/null +++ b/.github/workflows/python.yml @@ -0,0 +1,86 @@ +name: Python CI + +on: + workflow_call: + inputs: + os: + required: true + type: string + +env: + PYTHON_SRC: "src" + +permissions: + contents: read + +jobs: + python: + runs-on: ${{ inputs.os }} + strategy: + matrix: + target: [x86_64] + python-version: ['3.8', '3.9', '3.10', '3.11'] + name: Python ${{ matrix.python-version }} (${{ matrix.target }}) + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' # caching pip dependencies + + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.target }} + manylinux: manylinux2014 + container: quay.io/pypa/manylinux2014_x86_64 + args: --release --out dist -i ${{ matrix.python-version }} + sccache: 'true' + + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.os }}-${{ matrix.python-version }}-${{ matrix.target }}-wheels + path: dist + + - name: Install dependencies + run: | + if [ -f tests/requirements.txt ]; then python -m pip install -r tests/requirements.txt; fi + python -m pip install dist/*.whl + + - name: Package metadata + id: metadata + run: | + export PACKAGE_VERSION=$(pip inspect | jq -r '.installed | .[] | select(.metadata.name == "intel-sgx-ra") | .metadata.version') + echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> $GITHUB_OUTPUT + + - name: Code format with black + run: | + python -m black --check $PYTHON_SRC + + - name: Import check with isort + run: | + python -m isort --check --diff $PYTHON_SRC + + - name: Lint check with pylint + run: | + python -m pylint $PYTHON_SRC + + - name: Lint check with pycodestyle + run: | + python -m pycodestyle --max-line-length=90 --ignore=E203,W503 $PYTHON_SRC + + - name: Lint check with pydocstyle + run: | + python -m pydocstyle $PYTHON_SRC + + - name: Typecheck with MyPy + run: | + python -m mypy $PYTHON_SRC + + - name: Test with pytest + run: | + python -m pytest From c700ccce9a017e38bfe62bb8eaf4272a85caf9b3 Mon Sep 17 00:00:00 2001 From: grydz Date: Tue, 2 Apr 2024 16:21:16 +0400 Subject: [PATCH 4/6] Fix: use aware datetime object everywhere (with tzinfo) --- src/intel_sgx_ra/attest.py | 22 +++++++++++++--------- tests/test_pccs.py | 16 ++++++++-------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/intel_sgx_ra/attest.py b/src/intel_sgx_ra/attest.py index 4c5d32b..3cf0a14 100644 --- a/src/intel_sgx_ra/attest.py +++ b/src/intel_sgx_ra/attest.py @@ -2,7 +2,7 @@ import json import logging -from datetime import datetime +from datetime import datetime, timezone from hashlib import sha256 from typing import Any, Dict, Literal, Optional, Tuple, Union, cast @@ -61,7 +61,7 @@ def verify_pck_chain( True if success, raise exception otherwise. """ - now: datetime = datetime.utcnow() + now: datetime = datetime.now(timezone.utc) pck_ca_pk, root_ca_pk = ( cast(ec.EllipticCurvePublicKey, pck_ca_cert.public_key()), @@ -74,11 +74,11 @@ def verify_pck_chain( pck_cert.verify_directly_issued_by(pck_ca_cert) # Check expiration date of certificates - if not root_ca_cert.not_valid_before <= now <= root_ca_cert.not_valid_after: + if not root_ca_cert.not_valid_before_utc <= now <= root_ca_cert.not_valid_after_utc: raise CertificateError("Intel Root CA certificate has expired") - if not pck_ca_cert.not_valid_before <= now <= pck_ca_cert.not_valid_after: + if not pck_ca_cert.not_valid_before_utc <= now <= pck_ca_cert.not_valid_after_utc: raise CertificateError("Intel PCK CA certificate has expired") - if not pck_cert.not_valid_before <= now <= pck_cert.not_valid_after: + if not pck_cert.not_valid_before_utc <= now <= pck_cert.not_valid_after_utc: raise CertificateError("Intel PCK certificate has expired") # Check Intel Root CA signed Intel Root CA CRL and not revoked @@ -149,13 +149,17 @@ def verify_tcb( .. [1] https://api.portal.trustedservices.intel.com/documentation#pcs-tcb-info-model-v3 """ # noqa: E501 # pylint: disable=line-too-long - now: datetime = datetime.utcnow() + now: datetime = datetime.now(timezone.utc) tcb: Dict[str, Any] = json.loads(tcb_info) + next_update: datetime = datetime.fromisoformat( + # replace zero designator Z for the zero UTC offset (not parsed in Python 3.8) + tcb["tcbInfo"]["nextUpdate"].replace("Z", "+00:00") + ) assert tcb["tcbInfo"]["version"] == 3 assert tcb["tcbInfo"]["id"] == "SGX" - assert now < datetime.strptime(tcb["tcbInfo"]["nextUpdate"], "%Y-%m-%dT%H:%M:%SZ") + assert now < next_update root_ca_pk = cast(ec.EllipticCurvePublicKey, root_ca_cert.public_key()) @@ -164,9 +168,9 @@ def verify_tcb( tcb_cert.verify_directly_issued_by(root_ca_cert) # Check expiration date of certificates - if not root_ca_cert.not_valid_before <= now <= root_ca_cert.not_valid_after: + if not root_ca_cert.not_valid_before_utc <= now <= root_ca_cert.not_valid_after_utc: raise CertificateError("Intel Root CA certificate has expired") - if not tcb_cert.not_valid_before <= now <= tcb_cert.not_valid_after: + if not tcb_cert.not_valid_before_utc <= now <= tcb_cert.not_valid_after_utc: raise CertificateError("Intel TCB certificate has expired") try: diff --git a/tests/test_pccs.py b/tests/test_pccs.py index 4ee93cf..7c63bc6 100644 --- a/tests/test_pccs.py +++ b/tests/test_pccs.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from cryptography import x509 from cryptography.hazmat.primitives.asymmetric import ec @@ -8,7 +8,7 @@ def test_root_ca(data_path, pccs_url): quote: Quote = Quote.from_bytes((data_path / "quote.dat").read_bytes()) - now = datetime.now() + now = datetime.now(timezone.utc) _, _, root_ca_cert = [ x509.load_pem_x509_certificate(raw_cert) @@ -20,7 +20,7 @@ def test_root_ca(data_path, pccs_url): root_ca_cert.tbs_certificate_bytes, ec.ECDSA(root_ca_cert.signature_hash_algorithm), ) is None - assert root_ca_cert.not_valid_before <= now <= root_ca_cert.not_valid_after + assert root_ca_cert.not_valid_before_utc <= now <= root_ca_cert.not_valid_after_utc root_ca_crl = get_root_ca_crl(pccs_url) @@ -30,7 +30,7 @@ def test_root_ca(data_path, pccs_url): def test_pck_ca(data_path, pccs_url): quote: Quote = Quote.from_bytes((data_path / "quote.dat").read_bytes()) - now = datetime.now() + now = datetime.now(timezone.utc) _, pck_ca_cert, root_ca_cert = [ x509.load_pem_x509_certificate(raw_cert) @@ -43,7 +43,7 @@ def test_pck_ca(data_path, pccs_url): pck_ca_cert.tbs_certificate_bytes, ec.ECDSA(pck_ca_cert.signature_hash_algorithm), ) is None - assert pck_ca_cert.not_valid_before <= now <= pck_ca_cert.not_valid_after + assert pck_ca_cert.not_valid_before_utc <= now <= pck_ca_cert.not_valid_after_utc common_name, *_ = pck_ca_cert.subject.get_attributes_for_oid( x509.NameOID.COMMON_NAME @@ -60,7 +60,7 @@ def test_pck_ca(data_path, pccs_url): def test_pck(data_path, pccs_url): quote: Quote = Quote.from_bytes((data_path / "quote.dat").read_bytes()) - now = datetime.now() + now = datetime.now(timezone.utc) pck_cert, pck_ca_cert, root_ca_cert = [ x509.load_pem_x509_certificate(raw_cert) @@ -74,8 +74,8 @@ def test_pck(data_path, pccs_url): pck_cert.tbs_certificate_bytes, ec.ECDSA(pck_cert.signature_hash_algorithm), ) is None - assert pck_cert.not_valid_before <= now <= pck_cert.not_valid_after + assert pck_cert.not_valid_before_utc <= now <= pck_cert.not_valid_after_utc tcb_info, _root_ca_cert, tcb_cert = get_qe_identity(pccs_url) assert _root_ca_cert == root_ca_cert - assert tcb_cert.not_valid_before <= now <= tcb_cert.not_valid_after + assert tcb_cert.not_valid_before_utc <= now <= tcb_cert.not_valid_after_utc From cd33a5fa877fb163fd8aec214c531b0955793b62 Mon Sep 17 00:00:00 2001 From: grydz Date: Tue, 2 Apr 2024 16:24:35 +0400 Subject: [PATCH 5/6] Bump version to 2.3.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b051a76..3b39378 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "intel-sgx-ra" -version = "2.1.0" +version = "2.3.0" description = "Intel SGX Remote Attestation verification library" authors = [ {name = "Cosmian Tech", email = "tech@cosmian.com"}, From 2566249b39e11f93e029007bc49ae7c6d32d67a1 Mon Sep 17 00:00:00 2001 From: grydz Date: Tue, 2 Apr 2024 16:26:56 +0400 Subject: [PATCH 6/6] Update README --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8d6cfbb..b296f9c 100644 --- a/README.md +++ b/README.md @@ -14,21 +14,27 @@ $ pip install intel-sgx-ra ```console $ sgx-ra-verify --help -usage: sgx-ra-verify [-h] [--verbose] [--mrenclave MRENCLAVE] [--mrsigner MRSIGNER] {certificate,quote} ... +usage: sgx-ra-verify [-h] [--verbose] [--mrenclave HEXDIGEST] + [--mrsigner HEXDIGEST] + (--pccs-url URL | --azure-attestation) + {certificate,quote} ... -Intel SGX DCAP Quote verification +Intel SGX DCAP quote verification positional arguments: {certificate,quote} sub-command help - certificate Remote Attestation from X.509 certificate used for RA-TLS + certificate Remote Attestation from RA-TLS X.509 certificate quote Remote Attestation of a raw SGX quote optional arguments: -h, --help show this help message and exit --verbose Verbose mode - --mrenclave MRENCLAVE + --mrenclave HEXDIGEST Expected MRENCLAVE value in SGX quote - --mrsigner MRSIGNER Expected MRSIGNER value in SGX quote + --mrsigner HEXDIGEST Expected MRSIGNER value in SGX quote + --pccs-url URL Provisioning Certificate Cache Service URL (Intel + DCAP) + --azure-attestation Microsoft Azure Attestation Service (Azure DCAP) $ sgx-ra-utils --help usage: sgx-ra-utils [-h] [--verbose] {extract} ... @@ -36,7 +42,7 @@ Intel SGX DCAP Quote tools positional arguments: {extract} sub-command help - extract Extract Quote from X.509 certificate using RA-TLS + extract Extract Quote from RA-TLS X.509 certificate optional arguments: -h, --help show this help message and exit