You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by zf...@apache.org on 2020/05/13 04:51:51 UTC
[incubator-teaclave] branch master updated: Implement an example in
Python (builtin echo) (#292)
This is an automated email from the ASF dual-hosted git repository.
zfc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git
The following commit(s) were added to refs/heads/master by this push:
new 25dcc6c Implement an example in Python (builtin echo) (#292)
25dcc6c is described below
commit 25dcc6c0df6c274562c60655e3dc98e3f303cce8
Author: Mingshen Sun <bo...@mssun.me>
AuthorDate: Tue May 12 21:51:43 2020 -0700
Implement an example in Python (builtin echo) (#292)
* [tests] Use python3's BaseHTTPRequestHandler
* [examples] Add a builtin echo example written in python
---
cmake/UtilTargets.cmake | 4 +-
cmake/scripts/test.sh | 34 ++++-
examples/python/builtin_echo.py | 270 ++++++++++++++++++++++++++++++++++++
tests/scripts/simple_http_server.py | 17 ++-
4 files changed, 320 insertions(+), 5 deletions(-)
diff --git a/cmake/UtilTargets.cmake b/cmake/UtilTargets.cmake
index 7ef35e9..e53b32e 100644
--- a/cmake/UtilTargets.cmake
+++ b/cmake/UtilTargets.cmake
@@ -38,9 +38,11 @@ if(TEST_MODE)
add_custom_target(
run-functional-tests COMMAND ${TEACLAVE_COMMON_ENVS}
${MT_SCRIPT_DIR}/test.sh functional)
+ add_custom_target(run-examples COMMAND ${TEACLAVE_COMMON_ENVS}
+ ${MT_SCRIPT_DIR}/test.sh example)
else()
add_custom_target(
- run-test
+ run-tests
COMMAND
echo
"Note: Testing is not enabled in this build. Run cmake again with -DTEST_MODE=ON"
diff --git a/cmake/scripts/test.sh b/cmake/scripts/test.sh
index 87ce604..a7840cf 100755
--- a/cmake/scripts/test.sh
+++ b/cmake/scripts/test.sh
@@ -23,7 +23,7 @@ echo_title() {
}
start_storage_server() {
- python ${TEACLAVE_PROJECT_ROOT}/tests/scripts/simple_http_server.py 6789 &
+ python3 ${TEACLAVE_PROJECT_ROOT}/tests/scripts/simple_http_server.py 6789 &
}
run_unit_tests() {
@@ -133,6 +133,34 @@ run_functional_tests() {
cleanup
}
+run_examples() {
+ trap cleanup INT TERM ERR
+
+ echo_title "examples"
+ pushd ${TEACLAVE_SERVICE_INSTALL_DIR}
+ ./teaclave_authentication_service &
+ ./teaclave_storage_service &
+ sleep 3 # wait for authentication and storage service
+ ./teaclave_management_service &
+ ./teaclave_scheduler_service &
+ sleep 3 # wait for management service and scheduler_service
+ ./teaclave_access_control_service &
+ ./teaclave_frontend_service &
+ sleep 3 # wait for other services
+
+ start_storage_server
+
+ # Run tests of execution service separately
+ ./teaclave_execution_service &
+ sleep 3 # wait for execution services
+ popd
+
+ python3 ${TEACLAVE_PROJECT_ROOT}/examples/python/builtin_echo.py
+
+ # kill all background services
+ cleanup
+}
+
case "$1" in
"unit")
run_unit_tests
@@ -143,9 +171,13 @@ case "$1" in
"functional")
run_functional_tests
;;
+ "example")
+ run_examples
+ ;;
*)
run_unit_tests
run_integration_tests
run_functional_tests
+ run_examples
;;
esac
diff --git a/examples/python/builtin_echo.py b/examples/python/builtin_echo.py
new file mode 100644
index 0000000..7056bce
--- /dev/null
+++ b/examples/python/builtin_echo.py
@@ -0,0 +1,270 @@
+#!/usr/bin/env python3
+
+import socket
+import struct
+import ssl
+import json
+import base64
+import toml
+import os
+import time
+import sys
+
+from cryptography import x509
+from cryptography.hazmat.backends import default_backend
+
+from OpenSSL.crypto import load_certificate, FILETYPE_PEM, FILETYPE_ASN1
+from OpenSSL.crypto import X509Store, X509StoreContext
+from OpenSSL import crypto
+
+HOSTNAME = 'localhost'
+AUTHENTICATION_SERVICE_ADDRESS = (HOSTNAME, 7776)
+FRONTEND_SERVICE_ADDRESS = (HOSTNAME, 7777)
+CONTEXT = ssl._create_unverified_context()
+
+USER_ID = "example_user"
+USER_PASSWORD = "test_password"
+
+if os.environ.get('DCAP'):
+ AS_ROOT_CERT_FILENAME = "dcap_root_ca_cert.pem"
+else:
+ AS_ROOT_CERT_FILENAME = "ias_root_ca_cert.pem"
+
+if os.environ.get('TEACLAVE_PROJECT_ROOT'):
+ AS_ROOT_CA_CERT_PATH = os.environ['TEACLAVE_PROJECT_ROOT'] + \
+ "/keys/" + AS_ROOT_CERT_FILENAME
+ ENCLAVE_INFO_PATH = os.environ['TEACLAVE_PROJECT_ROOT'] + \
+ "/release/tests/enclave_info.toml"
+else:
+ AS_ROOT_CA_CERT_PATH = "../../keys/" + AS_ROOT_CERT_FILENAME
+ ENCLAVE_INFO_PATH = "../../release/tests/enclave_info.toml"
+
+
+def write_message(sock, message):
+ message = json.dumps(message)
+ message = message.encode()
+ sock.write(struct.pack(">Q", len(message)))
+ sock.write(message)
+
+
+def read_message(sock):
+ response_len = struct.unpack(">Q", sock.read(8))
+ response = sock.read(response_len[0])
+ response = json.loads(response)
+ return response
+
+
+def verify_report(cert, endpoint_name):
+ if os.environ.get('SGX_MODE') == 'SW':
+ return
+
+ cert = x509.load_der_x509_certificate(cert, default_backend())
+ ext = json.loads(cert.extensions[0].value.value)
+
+ report = bytes(ext["report"])
+ signature = bytes(ext["signature"])
+ signing_cert = bytes(ext["signing_cert"])
+ signing_cert = load_certificate(FILETYPE_ASN1, signing_cert)
+
+ # verify signing cert with AS root cert
+ with open(AS_ROOT_CA_CERT_PATH) as f:
+ as_root_ca_cert = f.read()
+ as_root_ca_cert = load_certificate(FILETYPE_PEM, as_root_ca_cert)
+ store = X509Store()
+ store.add_cert(as_root_ca_cert)
+ store.add_cert(signing_cert)
+ store_ctx = X509StoreContext(store, as_root_ca_cert)
+ store_ctx.verify_certificate()
+
+ # verify report's signature
+ crypto.verify(signing_cert, signature, bytes(ext["report"]), 'sha256')
+
+ report = json.loads(report)
+ quote = report['isvEnclaveQuoteBody']
+ quote = base64.b64decode(quote)
+
+ # get mr_enclave and mr_signer from the quote
+ mr_enclave = quote[112:112+32].hex()
+ mr_signer = quote[176:176+32].hex()
+
+ # get enclave_info
+ enclave_info = toml.load(ENCLAVE_INFO_PATH)
+
+ # verify mr_enclave and mr_signer
+ enclave_name = "teaclave_" + endpoint_name + "_service"
+ if mr_enclave != enclave_info[enclave_name]["mr_enclave"]:
+ raise Exception("mr_enclave error")
+
+ if mr_signer != enclave_info[enclave_name]["mr_signer"]:
+ raise Exception("mr_signer error")
+
+
+def user_register(channel, user_id, user_password):
+ message = {
+ "request": "user_register",
+ "id": user_id,
+ "password": user_password
+ }
+ write_message(channel, message)
+ read_message(channel)
+
+
+def user_login(channel, user_id, user_password):
+ message = {
+ "request": "user_login",
+ "id": user_id,
+ "password": user_password
+ }
+ write_message(channel, message)
+
+ response = read_message(channel)
+ assert(response["result"] == "ok")
+ return response["content"]["token"]
+
+
+def register_function(channel, user_id, token):
+ message = {
+ "metadata": {
+ "id": user_id,
+ "token": token
+ },
+ "request": "register_function",
+ "name": "builtin-echo",
+ "description": "Native Echo Function",
+ "executor_type": "builtin",
+ "public": True,
+ "payload": [],
+ "arguments": ["message"],
+ "inputs": [],
+ "outputs": [],
+ }
+ write_message(channel, message)
+
+ response = read_message(channel)
+ return response["content"]["function_id"]
+
+
+def create_task(channel, user_id, token, function_id, message):
+ message = {
+ "metadata": {
+ "id": user_id,
+ "token": token
+ },
+ "request": "create_task",
+ "function_id": function_id,
+ "function_arguments": {
+ "message": message,
+ },
+ "executor": "builtin",
+ "inputs_ownership": [],
+ "outputs_ownership": [],
+ }
+ write_message(channel, message)
+
+ response = read_message(channel)
+ return response["content"]["task_id"]
+
+
+def approve_task(channel, user_id, token, task_id):
+ message = {
+ "metadata": {
+ "id": user_id,
+ "token": token
+ },
+ "request": "approve_task",
+ "task_id": task_id,
+ }
+ write_message(channel, message)
+
+ response = read_message(channel)
+ assert(response["result"] == "ok")
+
+
+def invoke_task(channel, user_id, token, task_id):
+ message = {
+ "metadata": {
+ "id": user_id,
+ "token": token
+ },
+ "request": "invoke_task",
+ "task_id": task_id,
+ }
+ write_message(channel, message)
+
+ response = read_message(channel)
+ assert(response["result"] == "ok")
+
+
+def get_task_result(channel, user_id, token, task_id):
+ message = {
+ "metadata": {
+ "id": user_id,
+ "token": token
+ },
+ "request": "get_task",
+ "task_id": task_id,
+ }
+ while True:
+ write_message(channel, message)
+ response = read_message(channel)
+ time.sleep(1)
+ if response["content"]["status"] == 10:
+ break
+
+ return response["content"]["result"]["result"]["Ok"]["return_value"]
+
+
+class BuiltinEchoExample:
+ def __init__(self, user_id, user_password):
+ self.user_id = user_id
+ self.user_password = user_password
+
+ def echo(self, message="Hello, Teaclave!"):
+ sock = socket.create_connection(AUTHENTICATION_SERVICE_ADDRESS)
+ channel = CONTEXT.wrap_socket(sock, server_hostname=HOSTNAME)
+ cert = channel.getpeercert(binary_form=True)
+ verify_report(cert, "authentication")
+
+ print("[+] registering user")
+ user_register(channel, self.user_id, self.user_password)
+
+ print("[+] login")
+ token = user_login(channel, self.user_id, self.user_password)
+
+ sock = socket.create_connection(FRONTEND_SERVICE_ADDRESS)
+ channel = CONTEXT.wrap_socket(sock, server_hostname=HOSTNAME)
+ cert = channel.getpeercert(binary_form=True)
+ verify_report(cert, "frontend")
+
+ print("[+] registering function")
+ function_id = register_function(channel, self.user_id, token)
+
+ print("[+] creating task")
+ task_id = create_task(channel, self.user_id,
+ token, function_id, message)
+ print("[+] approving task")
+ approve_task(channel, self.user_id, token, task_id)
+
+ print("[+] invoking task")
+ invoke_task(channel, self.user_id, token, task_id)
+
+ print("[+] getting result")
+ result = get_task_result(channel, self.user_id, token, task_id)
+ print("[+] done")
+
+ return bytes(result)
+
+
+def main():
+ example = BuiltinEchoExample(USER_ID, USER_PASSWORD)
+ if len(sys.argv) > 1:
+ message = sys.argv[1]
+ rt = example.echo(message)
+ else:
+ rt = example.echo()
+
+ print("[+] function return: ", rt)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/scripts/simple_http_server.py b/tests/scripts/simple_http_server.py
index e3386c5..3fe4aa4 100644
--- a/tests/scripts/simple_http_server.py
+++ b/tests/scripts/simple_http_server.py
@@ -1,7 +1,11 @@
-import SimpleHTTPServer
+#!/usr/bin/env python3
+from http.server import SimpleHTTPRequestHandler
+import socketserver
+import sys
-class HTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+
+class HTTPRequestHandler(SimpleHTTPRequestHandler):
def do_PUT(self):
length = int(self.headers["Content-Length"])
@@ -14,4 +18,11 @@ class HTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
if __name__ == '__main__':
- SimpleHTTPServer.test(HandlerClass=HTTPRequestHandler)
+ if len(sys.argv) > 1:
+ port = int(sys.argv[1])
+ else:
+ port = 6789
+ socketserver.TCPServer.allow_reuse_address = True
+ with socketserver.TCPServer(("localhost", port), HTTPRequestHandler) as httpd:
+ print("serving at port", port)
+ httpd.serve_forever()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org