Coverage for admin/verify_sgx_attestation.py: 96%
97 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-11-18 02:59 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-11-18 02:59 +0000
1# The MIT License (MIT)
2#
3# Copyright (c) 2021 RSK Labs Ltd
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy of
6# this software and associated documentation files (the "Software"), to deal in
7# the Software without restriction, including without limitation the rights to
8# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9# of the Software, and to permit persons to whom the Software is furnished to do
10# so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
23from .misc import info, head, AdminError
24from .attestation_utils import PowHsmAttestationMessage, load_pubkeys, \
25 compute_pubkeys_hash, compute_pubkeys_output, \
26 get_sgx_root_of_trust
27from .x509_utils import get_intel_pcs_x509_crl
28from .sgx_utils import get_sgx_extensions, get_tcb_info, validate_tcb_info, \
29 get_qeid_info, validate_qeid_info
30from .x509_validator import X509CertificateValidator
31from .certificate import HSMCertificate, HSMCertificateV2ElementX509
34# ###################################################################################
35# As default root authority, we use the Provisioning Certification Root CA from Intel
36# The Provisioning Certification Root CA is available for download
37# from Intel, as described here:
38# https://api.portal.trustedservices.intel.com/content/documentation.html
40DEFAULT_ROOT_AUTHORITY = "https://certificates.trustedservices.intel.com/"\
41 "Intel_SGX_Provisioning_Certification_RootCA.pem"
43# ###################################################################################
45# #######################################################################################
46# SGX TCB information endpoint as per
47# https://api.portal.trustedservices.intel.com/content/documentation.html#pcs-tcb-info-v4
49SGX_TCB_INFO_ENDPOINT = "https://api.trustedservices.intel.com/sgx/certification/v4/tcb"
51# #######################################################################################
53# #######################################################################################
54# SGX QE identity information endpoint as per
55# https://api.portal.trustedservices.intel.com/content/
56# documentation.html#pcs-enclave-identity-v4
58SGX_QE_ID_ENDPOINT = "https://api.trustedservices.intel.com/sgx/certification/v4/"\
59 "qe/identity"
61# #######################################################################################
64def do_verify_attestation(options):
65 head("### -> Verify powHSM attestation", fill="#")
67 if options.attestation_certificate_file_path is None:
68 raise AdminError("No attestation certificate file given")
70 if options.pubkeys_file_path is None:
71 raise AdminError("No public keys file given")
73 # Certificate validator with Intel SGX PCS CRL getter
74 certificate_validator = X509CertificateValidator(get_intel_pcs_x509_crl)
75 HSMCertificateV2ElementX509.set_certificate_validator(certificate_validator)
77 # SGX extensions collateral getter
78 HSMCertificateV2ElementX509.set_collateral_getter(get_sgx_extensions)
80 # Load root authority
81 root_authority = options.root_authority or DEFAULT_ROOT_AUTHORITY
82 info(f"Attempting to gather root authority from {root_authority}...")
83 try:
84 root_of_trust = get_sgx_root_of_trust(root_authority)
85 info("Attempting to validate self-signed root authority...")
86 if not root_of_trust.is_valid(root_of_trust):
87 raise ValueError("Failed to validate self-signed root of trust")
88 except Exception as e:
89 raise AdminError(f"Invalid root authority {root_authority}: {e}")
90 info(f"Using {root_authority} as root authority")
92 # Load public keys, compute their hash and format them for output
93 try:
94 pubkeys_map = load_pubkeys(options.pubkeys_file_path)
95 pubkeys_hash = compute_pubkeys_hash(pubkeys_map)
96 pubkeys_output = compute_pubkeys_output(pubkeys_map)
97 except Exception as e:
98 raise AdminError(str(e))
100 # Load the given attestation key certificate
101 try:
102 att_cert = HSMCertificate.from_jsonfile(options.attestation_certificate_file_path)
103 except Exception as e:
104 raise AdminError(f"While loading the attestation certificate file: {str(e)}")
106 # Validate the certificate using the given root authority
107 # (this should be Intel's provisioning certification root
108 # CA certificate)
109 result = att_cert.validate_and_get_values(root_of_trust)
111 if "quote" not in result:
112 raise AdminError("Certificate does not contain a powHSM attestation")
114 powhsm_result = result["quote"]
115 if not powhsm_result["valid"]:
116 raise AdminError(
117 f"Invalid powHSM attestation: error "
118 f"validating '{powhsm_result["failed_element"]}'")
119 powhsm_collateral = powhsm_result["collateral"]
120 powhsm_result = powhsm_result["value"]
122 # Grab and verify TCB information
123 try:
124 if "quoting_enclave" not in powhsm_collateral:
125 raise AdminError("Certificate does not contain PCK collateral")
126 pck_collateral = powhsm_collateral["quoting_enclave"]
128 tcb_info_res = get_tcb_info(
129 SGX_TCB_INFO_ENDPOINT,
130 pck_collateral["fmspc"],
131 root_of_trust.certificate)
132 tcb_info = tcb_info_res["tcb_info"]["tcbInfo"]
134 tcb_validation_result = validate_tcb_info(pck_collateral, tcb_info)
135 if not tcb_validation_result["valid"]:
136 raise AdminError(f"TCB error: {tcb_validation_result["reason"]}")
138 if len(tcb_info_res["warnings"]) > 0:
139 info("***** TCB INFO WARNINGS *****")
140 for w in tcb_info_res["warnings"]:
141 info(w)
142 info("*****************************")
143 except Exception as e:
144 raise AdminError(f"While trying to verify TCB information: {e}")
146 # Grab and verify QE identity
147 try:
148 if "attestation" not in powhsm_collateral:
149 raise AdminError("Certificate does not contain QE collateral")
150 qe_collateral = powhsm_collateral["attestation"]
152 qeid_info_res = get_qeid_info(
153 SGX_QE_ID_ENDPOINT,
154 root_of_trust.certificate)
155 qeid_info = qeid_info_res["qeid_info"]["enclaveIdentity"]
157 qeid_validation_result = validate_qeid_info(qe_collateral, qeid_info)
158 if not qeid_validation_result["valid"]:
159 raise AdminError(f"QE ID error: {qeid_validation_result["reason"]}")
161 if len(qeid_info_res["warnings"]) > 0:
162 info("***** QE ID INFO WARNINGS *****")
163 for w in qeid_info_res["warnings"]:
164 info(w)
165 info("*****************************")
166 except Exception as e:
167 raise AdminError(f"While trying to verify QE ID information: {e}")
169 # powHSM specific validations
170 sgx_quote = powhsm_result["sgx_quote"]
171 powhsm_message = bytes.fromhex(powhsm_result["message"])
172 if not PowHsmAttestationMessage.is_header(powhsm_message):
173 raise AdminError(
174 f"Invalid powHSM attestation message header: {powhsm_message.hex()}")
176 try:
177 powhsm_message = PowHsmAttestationMessage(powhsm_message)
178 except Exception as e:
179 raise AdminError(f"Error parsing powHSM attestation message: {str(e)}")
180 reported_pubkeys_hash = powhsm_message.public_keys_hash
182 if reported_pubkeys_hash != pubkeys_hash:
183 raise AdminError(
184 f"powHSM attestation public keys hash mismatch: expected {pubkeys_hash.hex()}"
185 f" but attestation reports {reported_pubkeys_hash.hex()}"
186 )
188 signer_info = [
189 f"Hash: {pubkeys_hash.hex()}",
190 "",
191 f"Installed powHSM MRENCLAVE: {sgx_quote.report_body.mrenclave.hex()}",
192 f"Installed powHSM MRSIGNER: {sgx_quote.report_body.mrsigner.hex()}",
193 f"Installed powHSM version: {powhsm_message.version}",
194 ]
196 signer_info += [
197 f"Platform: {powhsm_message.platform}",
198 f"UD value: {powhsm_message.ud_value.hex()}",
199 f"Best block: {powhsm_message.best_block.hex()}",
200 f"Last transaction signed: {powhsm_message.last_signed_tx.hex()}",
201 f"Timestamp: {powhsm_message.timestamp}",
202 ]
204 tcb_info = [
205 f"Status: {tcb_validation_result["status"]}",
206 f"Issued: {tcb_validation_result["date"]}",
207 f"Advisories: {", ".join(tcb_validation_result["advisories"]) or "None"}",
208 f"TCB evaluation data number: {tcb_validation_result["edn"]}",
209 "SVNs:"
210 ]
212 tcb_info += map(lambda svn: f" - {svn}", tcb_validation_result["svns"])
214 qeid_info = [
215 f"Status: {qeid_validation_result["status"]}",
216 f"Issued: {qeid_validation_result["date"]}",
217 f"Advisories: {", ".join(qeid_validation_result["advisories"]) or "None"}",
218 f"TCB evaluation data number: {qeid_validation_result["edn"]}",
219 f"ISVSVN: {qeid_validation_result["isvsvn"]}",
220 ]
222 head(
223 ["powHSM verified with public keys:"] + pubkeys_output + signer_info,
224 fill="-",
225 )
227 head(
228 ["TCB Information:"] + tcb_info,
229 fill="-",
230 )
232 head(
233 ["QE Identity Information:"] + qeid_info,
234 fill="-",
235 )