Skip to content

Commit 8db7fb5

Browse files
New version of Attestation SDK and Local Verifier. (#23)
* 1. Added new version of Attestation SDK and Local GPU Verifier 2. Updated RIM documentation * 1. Patched Local verifier's logic in comparing vBIOS version numbers 2. Added 1.2.0 packages for Attestation SDK * Removed vBIOS RIMs from rims directory
1 parent 6296b7a commit 8db7fb5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+358
-3200
lines changed

guest_tools/attestation_sdk/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ The Attestation SDK offers developers easy-to-use APIs for implementing attestat
2727
- Local GPU Attestation (using NVIDIA NVML based Python libraries)
2828
- Remote GPU Attestation (using NVIDIA Remote Attestation Service)
2929

30-
Note: SDK v1.1.0 is still in Early Access Release (beta), and the APIs may undergo changes until the GA release.
30+
Note: SDK v1.2.0 is still in Early Access Release (beta), and the APIs may undergo changes until the GA release.
3131

3232
## Install Attestation SDK
3333

@@ -107,7 +107,7 @@ Please refer to the [sample implementation](tests/RemoteGPUTest.py)
107107
108108
## Version Info
109109
110-
SDK latest version - 1.1.0
110+
SDK latest version - 1.2.0
111111
112112
## Future Roadmap
113113
13.8 KB
Binary file not shown.
Binary file not shown.

guest_tools/attestation_sdk/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "nv-attestation-sdk"
3-
version = "1.1.0"
3+
version = "1.2.0"
44
authors = [
55
{name = "NVIDIA"},
66
]
@@ -14,7 +14,7 @@ classifiers = [
1414
]
1515
dependencies = [
1616
'pyjwt ~= 2.7.0',
17-
'verifier == 1.1.0',
17+
'verifier == 1.2.0',
1818
'requests ~= 2.31.0'
1919
]
2020
keywords = [

guest_tools/attestation_sdk/src/nv_attestation_sdk/attestation.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from enum import IntFlag
88
from enum import IntEnum
99
from datetime import datetime
10-
from nv_attestation_sdk.gpu import attest_gpu
10+
from nv_attestation_sdk.gpu import attest_gpu_local
11+
from nv_attestation_sdk.gpu import attest_gpu_remote
1112
from nv_attestation_sdk.attestation import *
1213
import secrets
1314
import jwt
@@ -93,6 +94,7 @@ def get_verifiers(cls) -> list:
9394
"""
9495
return cls._verifiers
9596

97+
9698
@classmethod
9799
def attest(cls) -> bool:
98100
"""
@@ -117,13 +119,13 @@ def attest(cls) -> bool:
117119
sdk_nonce_for_attestation = cls._generate_nonce()
118120

119121
if verifier[VerifierFields.DEVICE] == Devices.GPU and verifier[VerifierFields.ENVIRONMENT] == Environment.LOCAL:
120-
this_result, jwt_token = attest_gpu.attest_gpu_local(sdk_nonce_for_attestation)
122+
this_result, jwt_token = attest_gpu_local.attest(sdk_nonce_for_attestation)
121123

122124
# save the token with the verifier
123125
verifier[VerifierFields.JWT_TOKEN] = jwt_token
124126
attest_result = attest_result and this_result
125127
elif verifier[VerifierFields.DEVICE] == Devices.GPU and verifier[VerifierFields.ENVIRONMENT] == Environment.REMOTE:
126-
this_result, jwt_token = attest_gpu.attest_gpu_remote(sdk_nonce_for_attestation, verifier[VerifierFields.URL])
128+
this_result, jwt_token = attest_gpu_remote.attest(sdk_nonce_for_attestation, verifier[VerifierFields.URL])
127129

128130
# save the token with the verifier
129131
verifier[VerifierFields.JWT_TOKEN] = jwt_token
@@ -235,9 +237,9 @@ def _validate_token_internal(cls, policy:str, eat_token: str) -> bool:
235237
jwt_token = eat_claims[verifier_name]
236238
verifier = cls.get_verifier_by_name(verifier_name)
237239
if verifier_name == "LOCAL_GPU_CLAIMS":
238-
this_result = attest_gpu.validate_gpu_token_local(verifier, jwt_token, policy)
240+
this_result = attest_gpu_local.validate_gpu_token(verifier, jwt_token, policy)
239241
elif verifier_name == "REMOTE_GPU_CLAIMS":
240-
this_result = attest_gpu.validate_gpu_token_remote(verifier, jwt_token, policy)
242+
this_result = attest_gpu_remote.validate_gpu_token(verifier, jwt_token, policy)
241243
elif verifier_name == "TEST_CPU_CLAIMS":
242244
claims = jwt.decode( jwt_token, "notasecret", algorithms="HS256")
243245

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#
2+
# Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
#
4+
import json
5+
import jwt
6+
import requests
7+
import base64
8+
from cryptography.hazmat.primitives import serialization
9+
from cryptography.x509 import load_der_x509_certificate
10+
from cryptography.hazmat.backends import default_backend
11+
from nv_attestation_sdk import attestation
12+
from urllib.parse import urlparse
13+
from nv_attestation_sdk.gpu import gpu_utils
14+
15+
def validate_gpu_token(verifier, gpu_token: str, policy: str):
16+
if policy == "" or gpu_token == "":
17+
return False
18+
decoded_token = jwt.decode(gpu_token, algorithms='HS256', verify=False, key="secret")
19+
auth_rules = gpu_utils.get_auth_rules(policy)
20+
return gpu_utils.validate_gpu_token_with_policy(decoded_token, auth_rules)
21+
22+
def attest(nonce):
23+
attestation_result = False
24+
from verifier import cc_admin
25+
jwt_token = ""
26+
try:
27+
params = {"verbose": False,
28+
"test_no_gpu": False,
29+
"driver_rim": None,
30+
"vbios_rim": None,
31+
"user_mode": True,
32+
'rim_root_cert': None,
33+
'rim_service_url': None,
34+
'allow_hold_cert': True,
35+
'nonce': nonce}
36+
attestation_result, jwt_token = cc_admin.attest(params)
37+
except Exception as e:
38+
print("\tException: ", e)
39+
jwt_token = get_err_eat_token()
40+
return attestation_result, jwt_token
41+
42+
def get_err_eat_token(errCode=1, errMsg="GPU_ATTESTATION_ERR"):
43+
errJson = {'x-nv-err-message': errMsg, 'x-nv-err-code': errCode}
44+
return jwt.encode(errJson,
45+
'secret',
46+
"HS256")
47+
48+
def build_payload(nonce, evidence, cert_chain):
49+
data = dict()
50+
data['nonce'] = nonce
51+
encoded_evidence_bytes = evidence.encode("ascii")
52+
encoded_evidence = base64.b64encode(encoded_evidence_bytes)
53+
encoded_evidence = encoded_evidence.decode('utf-8')
54+
data['evidence'] = encoded_evidence
55+
data['arch'] = 'HOPPER'
56+
data['certificate'] = str(cert_chain)
57+
payload = json.dumps(data)
58+
return payload
59+

guest_tools/attestation_sdk/src/nv_attestation_sdk/gpu/attest_gpu.py renamed to guest_tools/attestation_sdk/src/nv_attestation_sdk/gpu/attest_gpu_remote.py

Lines changed: 13 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,40 +10,18 @@
1010
from cryptography.hazmat.backends import default_backend
1111
from nv_attestation_sdk import attestation
1212
from urllib.parse import urlparse
13+
from nv_attestation_sdk.gpu import gpu_utils
1314

14-
def validate_gpu_token_local(verifier, gpu_token: str, policy: str):
15-
if policy == "" or gpu_token == "":
16-
return False
17-
decoded_token = jwt.decode(gpu_token, algorithms='HS256', verify=False, key="secret")
18-
auth_rules = get_auth_rules(policy)
19-
return validate_gpu_token_with_policy(decoded_token, auth_rules)
20-
21-
def validate_gpu_token_with_policy(token: str, policy: str):
22-
for key in policy:
23-
if key in token:
24-
if type(policy[key]) is dict:
25-
return validate_gpu_token_with_policy(token[key], policy[key])
26-
else:
27-
if token[key] != policy[key]:
28-
print("\t[ERROR] Invalid token. Authorized claims does not match the appraisal policy: ", key)
29-
return False
30-
else:
31-
print("\t[ERROR] Invalid token. Authorized claims does not match the appraisal policy: ", key)
32-
return False
33-
return True
34-
35-
def get_auth_rules(policy: str):
36-
if policy == "":
37-
return None
38-
policy_obj = json.loads(policy)
39-
return policy_obj['authorization-rules']
15+
def attest(nonce, verifierUrl):
16+
gpu_evidence_list = generate_evidence(nonce)
17+
return verify_evidence(nonce, gpu_evidence_list, verifierUrl)
4018

4119
def create_jwks_url(verifier_url:str):
4220
parsed_url = urlparse(verifier_url)
4321
jwks_url = parsed_url.scheme + "://" + parsed_url.netloc + "/" + ".well-known/jwks.json"
4422
return jwks_url
4523

46-
def validate_gpu_token_remote(verifier, gpu_token: str, policy: str):
24+
def validate_gpu_token(verifier, gpu_token: str, policy: str):
4725
verifier_url = verifier[attestation.VerifierFields.URL]
4826
jwks_url = create_jwks_url(verifier_url)
4927
print("***** Validating Signature using JWKS endpont " + jwks_url + " ****** ")
@@ -84,8 +62,8 @@ def validate_gpu_token_remote(verifier, gpu_token: str, policy: str):
8462
json_formatted_str = json.dumps(decoded_token, indent=2)
8563
print("Decoded Token " , str(json_formatted_str))
8664
print("***** JWT token signature is valid. *****")
87-
auth_rules = get_auth_rules(policy)
88-
return validate_gpu_token_with_policy(decoded_token, auth_rules)
65+
auth_rules = gpu_utils.get_auth_rules(policy)
66+
return gpu_utils.validate_gpu_token_with_policy(decoded_token, auth_rules)
8967
except jwt.ExpiredSignatureError:
9068
print("JWT token has expired.")
9169
except jwt.InvalidTokenError as e:
@@ -94,33 +72,19 @@ def validate_gpu_token_remote(verifier, gpu_token: str, policy: str):
9472
print("No matching key or x5c key found for the provided kid.")
9573
return False
9674

97-
def attest_gpu_local(nonce):
98-
attestation_result = False
75+
def generate_evidence(nonce=""):
76+
print("generate_evidence")
9977
from verifier import cc_admin
100-
jwt_token = ""
101-
try:
102-
params = {"verbose": True,
103-
"test_no_gpu": False,
104-
"driver_rim": "/usr/share/nvidia/rim/RIM_GH100PROD.swidtag",
105-
"vbios_rim": None,
106-
"user_mode": True,
107-
'nonce': nonce}
108-
attestation_result, jwt_token = cc_admin.attest(params)
109-
except Exception as e:
110-
print("\tException: ", e)
111-
jwt_token = get_err_eat_token()
112-
return attestation_result, jwt_token
78+
gpu_evidence_list = cc_admin.collect_gpu_evidence(nonce)
79+
return gpu_evidence_list
11380

114-
def attest_gpu_remote(nonce, verifierUrl):
115-
from verifier import cc_admin
81+
def verify_evidence(nonce, gpu_evidence_list, verifierUrl="https://nras.attestation.nvidia.com/v1/attest/gpu"):
11682
attestation_result = False
11783
jwt_token = ""
11884
headers = {
11985
'Content-Type': 'application/json'
12086
}
12187
try:
122-
print("attest_gpu_remote")
123-
gpu_evidence_list = cc_admin.collect_gpu_evidence(nonce)
12488
for i , gpu_evidence in enumerate(gpu_evidence_list):
12589
gpu_evidence = gpu_evidence_list[i]
12690
current_gpu_status = False
@@ -135,7 +99,7 @@ def attest_gpu_remote(nonce, verifierUrl):
13599
current_gpu_status = True
136100
else:
137101
print("**** Attestation Failed ****")
138-
print("received NRAS response code: ", response.status_code)
102+
print("received NRAS response: ", reponse_json)
139103
#jwt_token = get_err_eat_token(reponse_json['errorCode'], reponse_json['message'])
140104
if i == 0:
141105
attestation_result = current_gpu_status
@@ -145,12 +109,6 @@ def attest_gpu_remote(nonce, verifierUrl):
145109
print("\tException: ", e)
146110
return attestation_result, jwt_token
147111

148-
def get_err_eat_token(errCode=1, errMsg="GPU_ATTESTATION_ERR"):
149-
errJson = {'x-nv-err-message': errMsg, 'x-nv-err-code': errCode}
150-
return jwt.encode(errJson,
151-
'secret',
152-
"HS256")
153-
154112
def build_payload(nonce, evidence, cert_chain):
155113
data = dict()
156114
data['nonce'] = nonce
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import json
2+
3+
def validate_gpu_token_with_policy(token: str, auth_rules: str):
4+
for key in auth_rules:
5+
if key in token:
6+
if type(auth_rules[key]) is dict:
7+
return validate_gpu_token_with_policy(token[key], auth_rules[key])
8+
else:
9+
if token[key] != auth_rules[key]:
10+
print("\t[ERROR] Invalid token. Authorized claims does not match the appraisal policy: ", key)
11+
return False
12+
else:
13+
print("\t[ERROR] Invalid token. Authorized claims does not match the appraisal policy: ", key)
14+
return False
15+
return True
16+
17+
def get_auth_rules(policy: str):
18+
if policy == "":
19+
return None
20+
policy_obj = json.loads(policy)
21+
return policy_obj['authorization-rules']

guest_tools/attestation_sdk/tests/RemoteGPUTest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@
2929

3030
print ("[RemoteGPUTest] call validate_token() - expecting True")
3131
print(client.validate_token(remote_att_result_policy))
32+
33+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5+
#
6+
from nv_attestation_sdk.gpu import attest_gpu_remote
7+
import secrets
8+
nonce = secrets.token_bytes(32).hex()
9+
10+
evidence = attest_gpu_remote.generate_evidence(nonce)
11+
print(evidence)
12+
13+
verify_result = attest_gpu_remote.verify_evidence(nonce,evidence, "https://nras.attestation.nvidia.com/v1/attest/gpu")
14+
15+
print(verify_result)

0 commit comments

Comments
 (0)