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

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. 

22 

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 

32 

33 

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 

39 

40DEFAULT_ROOT_AUTHORITY = "https://certificates.trustedservices.intel.com/"\ 

41 "Intel_SGX_Provisioning_Certification_RootCA.pem" 

42 

43# ################################################################################### 

44 

45# ####################################################################################### 

46# SGX TCB information endpoint as per 

47# https://api.portal.trustedservices.intel.com/content/documentation.html#pcs-tcb-info-v4 

48 

49SGX_TCB_INFO_ENDPOINT = "https://api.trustedservices.intel.com/sgx/certification/v4/tcb" 

50 

51# ####################################################################################### 

52 

53# ####################################################################################### 

54# SGX QE identity information endpoint as per 

55# https://api.portal.trustedservices.intel.com/content/ 

56# documentation.html#pcs-enclave-identity-v4 

57 

58SGX_QE_ID_ENDPOINT = "https://api.trustedservices.intel.com/sgx/certification/v4/"\ 

59 "qe/identity" 

60 

61# ####################################################################################### 

62 

63 

64def do_verify_attestation(options): 

65 head("### -> Verify powHSM attestation", fill="#") 

66 

67 if options.attestation_certificate_file_path is None: 

68 raise AdminError("No attestation certificate file given") 

69 

70 if options.pubkeys_file_path is None: 

71 raise AdminError("No public keys file given") 

72 

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) 

76 

77 # SGX extensions collateral getter 

78 HSMCertificateV2ElementX509.set_collateral_getter(get_sgx_extensions) 

79 

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") 

91 

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)) 

99 

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)}") 

105 

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) 

110 

111 if "quote" not in result: 

112 raise AdminError("Certificate does not contain a powHSM attestation") 

113 

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"] 

121 

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"] 

127 

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"] 

133 

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"]}") 

137 

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}") 

145 

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"] 

151 

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"] 

156 

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"]}") 

160 

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}") 

168 

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()}") 

175 

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 

181 

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 ) 

187 

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 ] 

195 

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 ] 

203 

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 ] 

211 

212 tcb_info += map(lambda svn: f" - {svn}", tcb_validation_result["svns"]) 

213 

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 ] 

221 

222 head( 

223 ["powHSM verified with public keys:"] + pubkeys_output + signer_info, 

224 fill="-", 

225 ) 

226 

227 head( 

228 ["TCB Information:"] + tcb_info, 

229 fill="-", 

230 ) 

231 

232 head( 

233 ["QE Identity Information:"] + qeid_info, 

234 fill="-", 

235 )