Skip to content
Last updated

Overview

We have successfully made an attested function call with the Blocky AS CLI and received the function's purported output. Before we trust that output, however, we should first verify that:

  • it was our function that was executed and
  • it was executed by a Blocky AS server and
  • that server was running in a TEE

Verify a WASM Function

  1. Let's start by looking at the entirety of the output returned by bky-as attest-fn-call:

    jq -r '.' out.json
    which outputs
    {
      "enclave_attested_application_public_key": {
        "enclave_attestation": "eyJwbGF0Zm9ybSI6InBsYWluIiwicGxhdGZvcm1fYXR0ZXN0YXRpb25zIjpbImV5SmtZWFJoSWpvaVpYbEthbVJZU2pKYVZqa3daVmhDYkVscWIybGpSRWt4VG0xemVFbHBkMmxhUjBZd1dWTkpOa2xyU1QwaUxDSnRaV0Z6ZFhKbGJXVnVkQ0k2ZXlKd2JHRjBabTl5YlNJNkluQnNZV2x1SWl3aVkyOWtaU0k2SW5Cc1lXbHVJbjE5IiwiZXlKa1lYUmhJam9pVkRKMFNXTnJTa05MTVdnMlVtNUpORlpGVWxaVWVscFBaVmQwVldKWVNYbFRWazV6V1RGR2NWcEVTVDBpTENKdFpXRnpkWEpsYldWdWRDSTZleUp3YkdGMFptOXliU0k2SW5Cc1lXbHVJaXdpWTI5a1pTSTZJbkJzWVdsdUluMTkiLCJleUprWVhSaElqb2lWVlZhTlUwd1RtcGFNRm8xVTBWa2VsRlZlR3RWU0U1UFZERldURkp0VWpaV1ZYQjRWMjVhYWs1cmJ6MGlMQ0p0WldGemRYSmxiV1Z1ZENJNmV5SndiR0YwWm05eWJTSTZJbkJzWVdsdUlpd2lZMjlrWlNJNkluQnNZV2x1SW4xOSIsImV5SmtZWFJoSWpvaVRIbDBiVlJYTVZOT01IUjJVMGR3U0dReVpIRlVWR2hNVFd0c1ZVNUVNR2xtVVQwOUlpd2liV1ZoYzNWeVpXMWxiblFpT25zaWNHeGhkR1p2Y20waU9pSndiR0ZwYmlJc0ltTnZaR1VpT2lKd2JHRnBiaUo5ZlE9PSIsImV5SmtZWFJoSWpvaVdtZzBkRzFGSzNZelVuWklhRlJ1UkhKRlFYVjZXRUZ3VFZwNksxRmpSekJyTVdVNFkzRk1iamRxTUQwaUxDSnRaV0Z6ZFhKbGJXVnVkQ0k2ZXlKd2JHRjBabTl5YlNJNkluQnNZV2x1SWl3aVkyOWtaU0k2SW5Cc1lXbHVJbjE5Il19",
        "claims": {
          "enclave_measurement": {
            "platform": "plain",
            "code": "plain"
          },
          "public_key": {
            "curve_type": "p256k1",
            "data": "BOkHrBB+XzFr8TDUO6NykTmr2ISlcQjd2QFy3CcgFyHGsALdPsNOUKFdzUJqZvc6J/+fMmR7KoHjGwgjM8K2IT4="
          }
        }
      },
      "transitive_attested_function_call": {
        "transitive_attestation": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA5ZjY0NGU5ODE1ZmQ5NGI0NGEwMzc2NzE4NTYzMzUzMzc2Yjk5ZmVhZmQ4ZmFmZThiYTFmNTllNzQ2ZTA3M2VhMTYzODhhZmI5YmU2MzM1NjYxNThkYzYyYmM0NzJhYjhlYWEzOWU0NGQ0ZTA3MDI3OTdiZTM0YmMwNGY2MWZlYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKaGVsbG9Xb3JsZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgGE2OWY3M2NjYTIzYTlhYzVjOGI1NjdkYzE4NWE3NTZlOTdjOTgyMTY0ZmUyNTg1OWUwZDFkY2MxNDc1YzgwYTYxNWIyMTIzYWYxZjVmOTRjMTFlM2U5NDAyYzNhYzU1OGY1MDAxOTlkOTViNmQzZTMwMTc1ODU4NjI4MWRjZDI2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1IZWxsbywgV29ybGQhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAYTY5ZjczY2NhMjNhOWFjNWM4YjU2N2RjMTg1YTc1NmU5N2M5ODIxNjRmZTI1ODU5ZTBkMWRjYzE0NzVjODBhNjE1YjIxMjNhZjFmNWY5NGMxMWUzZTk0MDJjM2FjNTU4ZjUwMDE5OWQ5NWI2ZDNlMzAxNzU4NTg2MjgxZGNkMjYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQftR9RME7XGzVjvn52lyuZ0r85PHw4bvN5zc+UW9arS8T6PZRnlZYsJtGIBuD+UVK367JR92KBZzY5mSlpzm0esBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
        "claims": {
          "hash_of_code": "9f644e9815fd94b44a0376718563353376b99feafd8fafe8ba1f59e746e073ea16388afb9be633566158dc62bc472ab8eaa39e44d4e0702797be34bc04f61fec",
          "function": "helloWorld",
          "hash_of_input": "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26",
          "output": "SGVsbG8sIFdvcmxkIQ==",
          "hash_of_secrets": "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"
        }
      }
    }

    The JSON output consists of two main entities: an enclave attestation containing the Blocky AS server's public key and a transitive attestation containing our function's inputs and outputs. The enclave attestation is used to verify the TEE platform and Blocky AS server code, whereas the transitive attestation is used to verify our function call.

  2. To verify the attestations, we need to provide bky-as with the expected TEE platform and Blocky AS server code measurement. This information is passed in via the config.toml:

    cat config.toml
    which outputs
    # a set of acceptable server enclave measurements for CLI to interact with
    acceptable_measurements = [
        # a measurement that is valid for when the server is running on a non-TEE environment
        { platform = "plain", code = "plain" },
    ]
    # token authorizing CLI's access to the server
    auth_token = "BLOCKY AS API TOKEN"
    
    # the server that the CLI interacts with.
    # `local-server` is a special host value that will start a local attestation
    # service server for testing and development. To interact with a production
    # server, replace `local-server` with the appropriate server endpoint.
    host = "local-server"

    The TEE platform and code measures here are "plain" because our example is configured to start and run a local non-TEE development server. In production, however, you would specify a real Blocky AS server endpoint, code measure, and TEE Platform (which we cover in Get a Developer API Key).

  3. Extract the enclave and transitive attestations from the output and pass them to bky-as verify-fn-call, where it will use the values in our config to validate the attestations.

    jq '{
    enclave_attested_application_public_key: .enclave_attested_application_public_key.enclave_attestation,
    transitive_attested_function_call: .transitive_attested_function_call.transitive_attestation
    }' out.json | bky-as verify-fn-call > verified.json
  4. If both attestations are authentic and correct, bky-as verify-fn-call will output the now verified function claims.

    jq -r '.transitive_attested_function_call.claims' verified.json
    which outputs
    {
      "hash_of_code": "9f644e9815fd94b44a0376718563353376b99feafd8fafe8ba1f59e746e073ea16388afb9be633566158dc62bc472ab8eaa39e44d4e0702797be34bc04f61fec",
      "function": "helloWorld",
      "hash_of_input": "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26",
      "output": "SGVsbG8sIFdvcmxkIQ==",
      "hash_of_secrets": "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"
    }
  5. The bky-as verify-fn-call only verifies that the enclave and transitive attestations were made by a Blocky AS server running within a TEE. It is your responsibility to use those transitively attested claims to verify that the hash_of_code, hash_of_input, and hash_of_secrets match your function code and call arguments.

    openssl dgst -sha3-512 ./main.wasm
    echo -n "" | openssl dgst -sha3-512
    which outputs
    SHA3-512(./main.wasm)= 9f644e9815fd94b44a0376718563353376b99feafd8fafe8ba1f59e746e073ea16388afb9be633566158dc62bc472ab8eaa39e44d4e0702797be34bc04f61fec
    SHA3-512(stdin)= a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26

    Since we did not pass any input or secrets to our function, an empty value is used when calculating hash_of_input and hash_of_secrets.

Next Steps

If you would like to learn more about TEEs and the attestation and verification process, check out Trusted Execution Environments in our Concepts section. Otherwise, continue on to the next section where we show you how to get a free developer API key so that you can run your functions on real Blocky AS servers and TEEs.