You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by ms...@apache.org on 2020/05/20 02:50:39 UTC

[incubator-teaclave] branch master updated: [sdk] Improve the Python SDK and update examples (#303)

This is an automated email from the ASF dual-hosted git repository.

mssun 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 8085e06  [sdk] Improve the Python SDK and update examples (#303)
8085e06 is described below

commit 8085e06babca89c33f174465774adb4995945fbb
Author: Mingshen Sun <bo...@mssun.me>
AuthorDate: Tue May 19 19:50:30 2020 -0700

    [sdk] Improve the Python SDK and update examples (#303)
---
 examples/python/builtin_echo.py | 193 +++++++------------------------------
 examples/python/mesapy_echo.py  | 207 +++++++++-------------------------------
 examples/python/utils.py        |  23 +++++
 sdk/python/teaclave.py          | 180 +++++++++++++++++++++++++++++++++-
 4 files changed, 278 insertions(+), 325 deletions(-)

diff --git a/examples/python/builtin_echo.py b/examples/python/builtin_echo.py
index 0a0a76d..fd980ce 100644
--- a/examples/python/builtin_echo.py
+++ b/examples/python/builtin_echo.py
@@ -1,149 +1,21 @@
 #!/usr/bin/env python3
 
-import socket
-import ssl
-import os
-import time
 import sys
 
-from teaclave import read_message, write_message, verify_report
-
-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 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"]
+from teaclave import (
+    AuthenticationService,
+    FrontendService,
+    AuthenticationClient,
+    FrontendClient
+)
+from utils import (
+    AUTHENTICATION_SERVICE_ADDRESS,
+    FRONTEND_SERVICE_ADDRESS,
+    AS_ROOT_CA_CERT_PATH,
+    ENCLAVE_INFO_PATH,
+    USER_ID,
+    USER_PASSWORD
+)
 
 
 class BuiltinEchoExample:
@@ -152,33 +24,40 @@ class BuiltinEchoExample:
         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(AS_ROOT_CA_CERT_PATH, ENCLAVE_INFO_PATH, cert, "authentication")
+        channel = AuthenticationService(AUTHENTICATION_SERVICE_ADDRESS,
+                                        AS_ROOT_CA_CERT_PATH,
+                                        ENCLAVE_INFO_PATH).connect()
+        client = AuthenticationClient(channel)
 
         print("[+] registering user")
-        user_register(channel, self.user_id, self.user_password)
+        client.user_register(self.user_id, self.user_password)
 
         print("[+] login")
-        token = user_login(channel, self.user_id, self.user_password)
+        token = client.user_login(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(AS_ROOT_CA_CERT_PATH, ENCLAVE_INFO_PATH, cert, "frontend")
+        channel = FrontendService(FRONTEND_SERVICE_ADDRESS,
+                                  AS_ROOT_CA_CERT_PATH,
+                                  ENCLAVE_INFO_PATH).connect()
+        metadata = {"id": self.user_id, "token": token}
+        client = FrontendClient(channel, metadata)
 
         print("[+] registering function")
-        function_id = register_function(channel, self.user_id, token)
+        function_id = client.register_function(
+            name="builtin-echo",
+            description="Native Echo Function",
+            executor_type="builtin",
+            arguments=["message"])
 
         print("[+] creating task")
-        task_id = create_task(channel, self.user_id,
-                              token, function_id, message)
+        task_id = client.create_task(function_id=function_id,
+                                     function_arguments={"message": message},
+                                     executor="builtin")
+
         print("[+] invoking task")
-        invoke_task(channel, self.user_id, token, task_id)
+        client.invoke_task(task_id)
 
         print("[+] getting result")
-        result = get_task_result(channel, self.user_id, token, task_id)
+        result = client.get_task_result(task_id)
         print("[+] done")
 
         return bytes(result)
diff --git a/examples/python/mesapy_echo.py b/examples/python/mesapy_echo.py
index 313af1c..6e6d1d8 100644
--- a/examples/python/mesapy_echo.py
+++ b/examples/python/mesapy_echo.py
@@ -1,155 +1,21 @@
 #!/usr/bin/env python3
 
-import socket
-import ssl
-import os
-import time
 import sys
 
-from teaclave import read_message, write_message, verify_report
-
-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 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):
-    payload = b"""
-def entrypoint(argv):
-    assert argv[0] == 'message'
-    assert argv[1] is not None
-    return argv[1]
-"""
-    message = {
-        "metadata": {
-            "id": user_id,
-            "token": token
-        },
-        "request": "register_function",
-        "name": "mesapy-echo",
-        "description": "An echo function implemented in Python",
-        "executor_type": "python",
-        "public": True,
-        "payload": list(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": "mesapy",
-        "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"]
+from teaclave import (
+    AuthenticationService,
+    FrontendService,
+    AuthenticationClient,
+    FrontendClient
+)
+from utils import (
+    AUTHENTICATION_SERVICE_ADDRESS,
+    FRONTEND_SERVICE_ADDRESS,
+    AS_ROOT_CA_CERT_PATH,
+    ENCLAVE_INFO_PATH,
+    USER_ID,
+    USER_PASSWORD
+)
 
 
 class MesaPyEchoExample:
@@ -158,33 +24,48 @@ class MesaPyEchoExample:
         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(AS_ROOT_CA_CERT_PATH, ENCLAVE_INFO_PATH, cert, "authentication")
+        channel = AuthenticationService(AUTHENTICATION_SERVICE_ADDRESS,
+                                        AS_ROOT_CA_CERT_PATH,
+                                        ENCLAVE_INFO_PATH).connect()
+        client = AuthenticationClient(channel)
 
         print("[+] registering user")
-        user_register(channel, self.user_id, self.user_password)
+        client.user_register(self.user_id, self.user_password)
 
         print("[+] login")
-        token = user_login(channel, self.user_id, self.user_password)
+        token = client.user_login(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(AS_ROOT_CA_CERT_PATH, ENCLAVE_INFO_PATH, cert, "frontend")
+        channel = FrontendService(FRONTEND_SERVICE_ADDRESS,
+                                  AS_ROOT_CA_CERT_PATH,
+                                  ENCLAVE_INFO_PATH).connect()
+        metadata = {"id": self.user_id, "token": token}
+        client = FrontendClient(channel, metadata)
 
         print("[+] registering function")
-        function_id = register_function(channel, self.user_id, token)
+
+        payload = b"""
+def entrypoint(argv):
+    assert argv[0] == 'message'
+    assert argv[1] is not None
+    return argv[1]
+        """
+        function_id = client.register_function(
+            name="mesapy-echo",
+            description="An echo function implemented in Python",
+            executor_type="python",
+            payload=list(payload),
+            arguments=["message"])
 
         print("[+] creating task")
-        task_id = create_task(channel, self.user_id,
-                              token, function_id, message)
+        task_id = client.create_task(function_id=function_id,
+                                     function_arguments={"message": message},
+                                     executor="mesapy")
+
         print("[+] invoking task")
-        invoke_task(channel, self.user_id, token, task_id)
+        client.invoke_task(task_id)
 
         print("[+] getting result")
-        result = get_task_result(channel, self.user_id, token, task_id)
+        result = client.get_task_result(task_id)
         print("[+] done")
 
         return bytes(result)
diff --git a/examples/python/utils.py b/examples/python/utils.py
new file mode 100644
index 0000000..2bd4725
--- /dev/null
+++ b/examples/python/utils.py
@@ -0,0 +1,23 @@
+import os
+
+HOSTNAME = 'localhost'
+AUTHENTICATION_SERVICE_ADDRESS = (HOSTNAME, 7776)
+FRONTEND_SERVICE_ADDRESS = (HOSTNAME, 7777)
+
+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"
+
diff --git a/sdk/python/teaclave.py b/sdk/python/teaclave.py
index c7b7421..7e1e4c5 100644
--- a/sdk/python/teaclave.py
+++ b/sdk/python/teaclave.py
@@ -5,6 +5,9 @@ import json
 import base64
 import toml
 import os
+import time
+import ssl
+import socket
 
 from cryptography import x509
 from cryptography.hazmat.backends import default_backend
@@ -14,9 +17,175 @@ from OpenSSL.crypto import X509Store, X509StoreContext
 from OpenSSL import crypto
 
 
+class RequestEncoder(json.JSONEncoder):
+    def default(self, o):
+        return o.__dict__
+
+
+class UserRegisterReqeust:
+    def __init__(self, user_id, user_password):
+        self.request = "user_register"
+        self.id = user_id
+        self.password = user_password
+
+
+class UserLoginRequest:
+    def __init__(self, user_id, user_password):
+        self.request = "user_login"
+        self.id = user_id
+        self.password = user_password
+
+
+class AuthenticationClient:
+    def __init__(self, channel):
+        self.channel = channel
+
+    def user_register(self, user_id, user_password):
+        request = UserRegisterReqeust(user_id, user_password)
+        write_message(self.channel, request)
+        return read_message(self.channel)
+
+    def user_login(self, user_id, user_password):
+        request = UserLoginRequest(user_id, user_password)
+        write_message(self.channel, request)
+        response = read_message(self.channel)
+        return response["content"]["token"]
+
+
+class AuthenticationService:
+    context = ssl._create_unverified_context()
+
+    def __init__(self, address, as_root_ca_cert_path, enclave_info_path):
+        self.address = address
+        self.as_root_ca_cert_path = as_root_ca_cert_path
+        self.enclave_info_path = enclave_info_path
+
+    def connect(self):
+        sock = socket.create_connection(self.address)
+        channel = self.context.wrap_socket(sock,
+                                           server_hostname=self.address[0])
+        cert = channel.getpeercert(binary_form=True)
+        verify_report(self.as_root_ca_cert_path, self.enclave_info_path, cert,
+                      "authentication")
+
+        return channel
+
+
+class FrontendService:
+    context = ssl._create_unverified_context()
+
+    def __init__(self, address, as_root_ca_cert_path, enclave_info_path):
+        self.address = address
+        self.as_root_ca_cert_path = as_root_ca_cert_path
+        self.enclave_info_path = enclave_info_path
+
+    def connect(self):
+        sock = socket.create_connection(self.address)
+        channel = self.context.wrap_socket(sock,
+                                           server_hostname=self.address[0])
+        cert = channel.getpeercert(binary_form=True)
+        verify_report(self.as_root_ca_cert_path, self.enclave_info_path, cert,
+                      "frontend")
+
+        return channel
+
+
+class RegisterFunctionRequest:
+    def __init__(self, metadata, name, description, executor_type, public,
+                 payload, arguments, inputs, outputs):
+        self.request = "register_function"
+        self.metadata = metadata
+        self.name = name
+        self.description = description
+        self.executor_type = executor_type
+        self.public = public
+        self.payload = payload
+        self.arguments = arguments
+        self.inputs = inputs
+        self.outputs = outputs
+
+
+class CreateTaskRequest:
+    def __init__(self, metadata, function_id, function_arguments, executor,
+                 inputs_ownership, outputs_ownership):
+        self.request = "create_task"
+        self.metadata = metadata
+        self.function_id = function_id
+        self.function_arguments = function_arguments
+        self.executor = executor
+        self.inputs_ownership = inputs_ownership
+        self.outputs_ownership = outputs_ownership
+
+
+class InvokeTaskRequest:
+    def __init__(self, metadata, task_id):
+        self.request = "invoke_task"
+        self.metadata = metadata
+        self.task_id = task_id
+
+
+class GetTaskRequest:
+    def __init__(self, metadata, task_id):
+        self.request = "get_task"
+        self.metadata = metadata
+        self.task_id = task_id
+
+
+class FrontendClient:
+    def __init__(self, channel, metadata):
+        self.channel = channel
+        self.metadata = metadata
+
+    def register_function(self,
+                          name,
+                          description,
+                          executor_type,
+                          public=True,
+                          payload=[],
+                          arguments=[],
+                          inputs=[],
+                          outputs=[]):
+        request = RegisterFunctionRequest(self.metadata, name, description,
+                                          executor_type, public, payload,
+                                          arguments, inputs, outputs)
+        write_message(self.channel, request)
+        response = read_message(self.channel)
+        return response["content"]["function_id"]
+
+    def create_task(self,
+                    function_id,
+                    function_arguments,
+                    executor,
+                    inputs_ownership=[],
+                    outputs_ownership=[]):
+        request = CreateTaskRequest(self.metadata, function_id,
+                                    function_arguments, executor,
+                                    inputs_ownership, outputs_ownership)
+        write_message(self.channel, request)
+        response = read_message(self.channel)
+        return response["content"]["task_id"]
+
+    def invoke_task(self, task_id):
+        request = InvokeTaskRequest(self.metadata, task_id)
+        write_message(self.channel, request)
+        response = read_message(self.channel)
+        assert (response["result"] == "ok")
+
+    def get_task_result(self, task_id):
+        request = GetTaskRequest(self.metadata, task_id)
+
+        while True:
+            write_message(self.channel, request)
+            response = read_message(self.channel)
+            time.sleep(1)
+            if response["content"]["status"] == 10:
+                break
+
+        return response["content"]["result"]["result"]["Ok"]["return_value"]
+
+
 def write_message(sock, message):
-    message = json.dumps(message)
-    message = message.encode()
+    message = json.dumps(message, cls=RequestEncoder).encode()
     sock.write(struct.pack(">Q", len(message)))
     sock.write(message)
 
@@ -28,7 +197,8 @@ def read_message(sock):
     return response
 
 
-def verify_report(as_root_ca_cert_path, enclave_info_path, cert, endpoint_name):
+def verify_report(as_root_ca_cert_path, enclave_info_path, cert,
+                  endpoint_name):
     if os.environ.get('SGX_MODE') == 'SW':
         return
 
@@ -58,8 +228,8 @@ def verify_report(as_root_ca_cert_path, enclave_info_path, cert, endpoint_name):
     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()
+    mr_enclave = quote[112:112 + 32].hex()
+    mr_signer = quote[176:176 + 32].hex()
 
     # get enclave_info
     enclave_info = toml.load(enclave_info_path)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org