зеркало из https://github.com/microsoft/CCF.git
[release/2.x] Support new quote formats in 2.x (#4098)
This commit is contained in:
Родитель
2503f65b18
Коммит
bde145a643
|
@ -1 +1 @@
|
|||
It's a new dawn, there is a new heatwave...
|
||||
It's a new dawn, there is a new heatwave....
|
||||
|
|
|
@ -591,7 +591,9 @@
|
|||
},
|
||||
"QuoteFormat": {
|
||||
"enum": [
|
||||
"OE_SGX_v1"
|
||||
"OE_SGX_v1",
|
||||
"Insecure_Virtual",
|
||||
"AMD_SEV_SNP_v1"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -813,7 +815,7 @@
|
|||
"info": {
|
||||
"description": "This API provides public, uncredentialed access to service and node state.",
|
||||
"title": "CCF Public Node API",
|
||||
"version": "2.28.0"
|
||||
"version": "2.29.0"
|
||||
},
|
||||
"openapi": "3.0.0",
|
||||
"paths": {
|
||||
|
|
|
@ -10,10 +10,16 @@ namespace ccf
|
|||
{
|
||||
enum class QuoteFormat
|
||||
{
|
||||
oe_sgx_v1 = 0
|
||||
oe_sgx_v1 = 0,
|
||||
insecure_virtual = 1,
|
||||
amd_sev_snp_v1 = 2
|
||||
};
|
||||
|
||||
DECLARE_JSON_ENUM(QuoteFormat, {{QuoteFormat::oe_sgx_v1, "OE_SGX_v1"}})
|
||||
DECLARE_JSON_ENUM(
|
||||
QuoteFormat,
|
||||
{{QuoteFormat::oe_sgx_v1, "OE_SGX_v1"},
|
||||
{QuoteFormat::insecure_virtual, "Insecure_Virtual"},
|
||||
{QuoteFormat::amd_sev_snp_v1, "AMD_SEV_SNP_v1"}})
|
||||
|
||||
struct QuoteInfo
|
||||
{
|
||||
|
|
|
@ -139,14 +139,14 @@ namespace ccf
|
|||
{
|
||||
case QuoteVerificationResult::Failed:
|
||||
return std::make_pair(
|
||||
HTTP_STATUS_INTERNAL_SERVER_ERROR, "Quote could not be verified");
|
||||
HTTP_STATUS_UNAUTHORIZED, "Quote could not be verified");
|
||||
case QuoteVerificationResult::FailedCodeIdNotFound:
|
||||
return std::make_pair(
|
||||
HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||
HTTP_STATUS_UNAUTHORIZED,
|
||||
"Quote does not contain known enclave measurement");
|
||||
case QuoteVerificationResult::FailedInvalidQuotedPublicKey:
|
||||
return std::make_pair(
|
||||
HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||
HTTP_STATUS_UNAUTHORIZED,
|
||||
"Quote report data does not contain node's public key hash");
|
||||
default:
|
||||
return std::make_pair(
|
||||
|
@ -370,7 +370,7 @@ namespace ccf
|
|||
openapi_info.description =
|
||||
"This API provides public, uncredentialed access to service and node "
|
||||
"state.";
|
||||
openapi_info.document_version = "2.28.0";
|
||||
openapi_info.document_version = "2.29.0";
|
||||
}
|
||||
|
||||
void init_handlers() override
|
||||
|
|
|
@ -16,6 +16,7 @@ import infra.crypto
|
|||
from datetime import datetime
|
||||
from infra.checker import check_can_progress
|
||||
from infra.runner import ConcurrentRunner
|
||||
import http
|
||||
|
||||
from loguru import logger as LOG
|
||||
|
||||
|
@ -375,6 +376,93 @@ def test_version(network, args):
|
|||
)
|
||||
|
||||
|
||||
@reqs.description("Issue fake join requests as untrusted client")
|
||||
def test_issue_fake_join(network, args):
|
||||
primary, _ = network.find_primary()
|
||||
|
||||
# Assemble dummy join request body
|
||||
net = {"bind_address": "0:0"}
|
||||
req = {}
|
||||
req["node_info_network"] = {
|
||||
"node_to_node_interface": net,
|
||||
"rpc_interfaces": {"name": net},
|
||||
}
|
||||
req["consensus_type"] = "CFT"
|
||||
req["startup_seqno"] = 0
|
||||
with open(
|
||||
os.path.join(network.common_dir, "member0_enc_pubk.pem"), "r", encoding="utf-8"
|
||||
) as f:
|
||||
req["public_encryption_key"] = f.read()
|
||||
with primary.client(identity="user0") as c:
|
||||
LOG.info("Join with SGX dummy quote (2.x node)")
|
||||
req["quote_info"] = {"format": "OE_SGX_v1", "quote": "", "endorsements": ""}
|
||||
r = c.post("/node/join", body=req)
|
||||
if args.enclave_type == "virtual":
|
||||
assert r.status_code == http.HTTPStatus.OK
|
||||
assert r.body.json()["node_status"] == ccf.ledger.NodeStatus.PENDING.value
|
||||
else:
|
||||
assert r.status_code == http.HTTPStatus.UNAUTHORIZED
|
||||
assert (
|
||||
r.body.json()["error"]["code"] == "InvalidQuote"
|
||||
), "Quote verification should fail when OE_SGX_v1 is specified"
|
||||
|
||||
LOG.info("Join with SGX real quote, but different TLS key")
|
||||
# First, retrieve real quote from primary node
|
||||
r = c.get("/node/quotes/self").body.json()
|
||||
req["quote_info"] = {
|
||||
"format": "OE_SGX_v1",
|
||||
"quote": r["raw"],
|
||||
"endorsements": r["endorsements"],
|
||||
}
|
||||
r = c.post("/node/join", body=req)
|
||||
if args.enclave_type == "virtual":
|
||||
# Quote is not verified by virtual node
|
||||
assert r.status_code == http.HTTPStatus.OK
|
||||
assert r.body.json()["node_status"] == ccf.ledger.NodeStatus.PENDING.value
|
||||
else:
|
||||
assert r.status_code == http.HTTPStatus.UNAUTHORIZED
|
||||
assert r.body.json()["error"]["code"] == "InvalidQuote"
|
||||
assert (
|
||||
r.body.json()["error"]["message"]
|
||||
== "Quote report data does not contain node's public key hash"
|
||||
)
|
||||
|
||||
LOG.info("Join with virtual quote (3.x node)")
|
||||
req["quote_info"] = {
|
||||
"format": "Insecure_Virtual",
|
||||
"quote": "",
|
||||
"endorsements": "",
|
||||
}
|
||||
r = c.post("/node/join", body=req)
|
||||
if args.enclave_type == "virtual":
|
||||
assert r.status_code == http.HTTPStatus.OK
|
||||
assert r.body.json()["node_status"] == ccf.ledger.NodeStatus.PENDING.value
|
||||
else:
|
||||
assert r.status_code == http.HTTPStatus.UNAUTHORIZED
|
||||
assert (
|
||||
r.body.json()["error"]["code"] == "InvalidQuote"
|
||||
), "Virtual node must never join SGX network"
|
||||
|
||||
LOG.info("Join with AMD SEV-SNP quote")
|
||||
req["quote_info"] = {
|
||||
"format": "AMD_SEV_SNP_v1",
|
||||
"quote": "",
|
||||
"endorsements": "",
|
||||
}
|
||||
r = c.post("/node/join", body=req)
|
||||
if args.enclave_type == "virtual":
|
||||
assert r.status_code == http.HTTPStatus.OK
|
||||
assert r.body.json()["node_status"] == ccf.ledger.NodeStatus.PENDING.value
|
||||
else:
|
||||
assert r.status_code == http.HTTPStatus.UNAUTHORIZED
|
||||
# https://github.com/microsoft/CCF/issues/4072
|
||||
assert (
|
||||
r.body.json()["error"]["code"] == "InvalidQuote"
|
||||
), "SEV-SNP node cannot currently join SGX network"
|
||||
|
||||
return network
|
||||
|
||||
|
||||
@reqs.description("Replace a node on the same addresses")
|
||||
@reqs.can_kill_n_nodes(1)
|
||||
def test_node_replacement(network, args):
|
||||
|
@ -590,6 +678,7 @@ def run(args):
|
|||
network.start_and_open(args)
|
||||
|
||||
test_version(network, args)
|
||||
test_issue_fake_join(network, args)
|
||||
|
||||
if args.consensus != "BFT":
|
||||
test_add_node_invalid_service_cert(network, args)
|
||||
|
|
Загрузка…
Ссылка в новой задаче