forked from Phala-Network/dcap-qvl
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_case.py
More file actions
executable file
·186 lines (150 loc) · 5.77 KB
/
test_case.py
File metadata and controls
executable file
·186 lines (150 loc) · 5.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env python3
"""
Python implementation of test_case CLI tool for DCAP quote verification.
Usage:
test_case.py <command> [args...]
Commands:
verify <quote_file> <collateral_file> [root_ca_file]
get-collateral [--pccs-url URL] <quote_file>
Exit codes:
0 - Command successful
1 - Command failed
2 - Unexpected error (file not found, parse error, etc.)
Output:
Prints result to stdout
Prints errors to stderr
"""
import sys
import json
import asyncio
import argparse
import time
from pathlib import Path
# Try to import dcap_qvl
try:
import dcap_qvl
except ImportError:
print("Error: dcap_qvl module not found", file=sys.stderr)
print("Please install the Python bindings first:", file=sys.stderr)
print(" cd python-bindings && pip install -e .", file=sys.stderr)
sys.exit(2)
def cmd_verify(args):
"""Verify a quote with collateral."""
quote_file = Path(args.quote_file)
collateral_file = Path(args.collateral_file)
root_ca_file = Path(args.root_ca_file) if args.root_ca_file else None
# Read quote
try:
quote_bytes = quote_file.read_bytes()
except Exception as e:
print(f"Failed to read quote file: {e}", file=sys.stderr)
return 2
# Read collateral
try:
collateral_json = collateral_file.read_text()
collateral = json.loads(collateral_json)
except Exception as e:
print(f"Failed to read collateral file: {e}", file=sys.stderr)
return 2
# Read custom root CA if provided
root_ca_der = None
if root_ca_file:
try:
root_ca_der = root_ca_file.read_bytes()
except Exception as e:
print(f"Failed to read root CA file: {e}", file=sys.stderr)
return 2
# Use current time like the Rust CLI
now_secs = int(time.time())
try:
# Convert collateral dict to QuoteCollateralV3 object
collateral_obj = dcap_qvl.QuoteCollateralV3.from_json(json.dumps(collateral))
# Verify using the Rust backend
if root_ca_der:
# Use custom root CA for testing
result = dcap_qvl.verify_with_root_ca(
quote_bytes, collateral_obj, root_ca_der, now_secs
)
else:
# Use production Intel root CA
result = dcap_qvl.verify(quote_bytes, collateral_obj, now_secs)
# Verification successful
print("Verification successful")
print(f"Status: {result.status}")
return 0
except Exception as e:
# Verification failed - match Rust CLI output format
print(f"Verification failed: {e}", file=sys.stderr)
# Try to extract cause chain - match Rust CLI format
cause = e.__cause__
while cause:
print(f" Caused by: {cause}", file=sys.stderr)
cause = cause.__cause__
return 1
async def cmd_get_collateral(args):
"""Fetch collateral from PCCS."""
quote_file = Path(args.quote_file)
pccs_url = args.pccs_url
# Read quote
try:
quote_bytes = quote_file.read_bytes()
except Exception as e:
print(f"Failed to read quote file: {e}", file=sys.stderr)
return 2
try:
# Use the same get_collateral function as Rust (parses quote properly)
collateral = await dcap_qvl.get_collateral(pccs_url, quote_bytes)
if not collateral or not hasattr(collateral, 'tcb_info_issuer_chain'):
print(json.dumps({"error": "Collateral missing required fields"}))
return 1
# Output collateral JSON directly
if hasattr(collateral, 'to_json'):
print(collateral.to_json())
else:
print(json.dumps(collateral.__dict__))
return 0
except Exception as e:
print(json.dumps({"error": str(e)}))
return 1
def main():
"""Main entry point for test_case."""
parser = argparse.ArgumentParser(
description="Python implementation of test_case CLI tool for DCAP quote verification",
add_help=False
)
parser.add_argument('command', choices=['verify', 'get-collateral'],
help='Command to run')
parser.add_argument('--help', action='store_true', help='Show help message')
# Parse only the command first
if len(sys.argv) < 2:
parser.print_help()
print("\nCommands:")
print(" verify <quote_file> <collateral_file> [root_ca_file]")
print(" Verify a quote with collateral")
print(" get-collateral [--pccs-url URL] <quote_file>")
print(" Fetch collateral from PCCS")
sys.exit(2)
cmd = sys.argv[1]
if cmd == '--help' or (len(sys.argv) == 2 and cmd == 'help'):
parser.print_help()
sys.exit(0)
if cmd == 'verify':
sub_parser = argparse.ArgumentParser(prog='test_case.py verify')
sub_parser.add_argument('quote_file', help='Path to quote file')
sub_parser.add_argument('collateral_file', help='Path to collateral JSON file')
sub_parser.add_argument('root_ca_file', nargs='?', help='Optional path to custom root CA DER file')
args = sub_parser.parse_args(sys.argv[2:])
sys.exit(cmd_verify(args))
elif cmd == 'get-collateral':
sub_parser = argparse.ArgumentParser(prog='test_case.py get-collateral')
sub_parser.add_argument('--pccs-url',
default='https://pccs.phala.network/tdx/certification/v4',
help='PCCS URL (default: https://pccs.phala.network/tdx/certification/v4)')
sub_parser.add_argument('quote_file', help='Path to quote file')
args = sub_parser.parse_args(sys.argv[2:])
sys.exit(asyncio.run(cmd_get_collateral(args)))
else:
print(f"Unknown command: {cmd}", file=sys.stderr)
sys.exit(2)
if __name__ == "__main__":
main()