From: l00643034 <lishengjie12@huawei.com>
Date: Wed, 12 Jun 2024 22:45:00 +0800
Subject: [PATCH] add virtcca

---
 CMakeLists.txt                                |  17 +-
 build.sh                                      | 309 +++++++++++++
 cmake/CustomInstallDirs.cmake                 |  26 +-
 samples/CMakeLists.txt                        |   2 +
 samples/rats-tls-client/CMakeLists.txt        |   2 +-
 samples/rats-tls-server/CMakeLists.txt        |   2 +-
 samples/sgx-stub-enclave/CMakeLists.txt       |   2 +-
 samples/sgx-stub-enclave/sgx_stub_ecall.c     |   6 +-
 samples/virtcca-client/CMakeLists.txt         |  39 ++
 samples/virtcca-client/ima_measure.c          | 414 ++++++++++++++++++
 samples/virtcca-client/inc/ima_measure.h      |  17 +
 samples/virtcca-client/rats-client.c          | 309 +++++++++++++
 samples/virtcca-client/utils/CMakeLists.txt   |  19 +
 samples/virtcca-server/CMakeLists.txt         |  25 ++
 samples/virtcca-server/rats-server.c          | 350 +++++++++++++++
 src/CMakeLists.txt                            |   9 +-
 src/api/rats_tls_init.c                       |   8 -
 src/attesters/CMakeLists.txt                  |   4 +
 src/attesters/api/enclave_attester_register.c |  29 +-
 src/attesters/csv/collect_evidence.c          |   3 +-
 src/attesters/csv/pre_init.c                  |  11 +-
 .../internal/rtls_enclave_attester_load_all.c |  15 +-
 src/attesters/tdx-ecdsa/pre_init.c            |   1 +
 src/attesters/virtcca/CMakeLists.txt          |  30 ++
 src/attesters/virtcca/cleanup.c               |  14 +
 src/attesters/virtcca/collect_evidence.c      |  67 +++
 src/attesters/virtcca/init.c                  |  29 ++
 src/attesters/virtcca/main.c                  |  33 ++
 src/attesters/virtcca/pre_init.c              |   9 +
 src/core/cpu.c                                | 123 ++++--
 src/core/dice.c                               |  66 ++-
 src/core/main.c                               |   4 +-
 src/core/rtls_common.c                        |  80 ++--
 src/core/rtls_core_generate_certificate.c     |  33 +-
 .../internal/rtls_crypto_wrapper_load_all.c   |  18 +-
 src/include/internal/attester.h               |   2 +
 src/include/internal/core.h                   |   2 +
 src/include/internal/cpu.h                    |   1 +
 src/include/internal/crypto_wrapper.h         |   2 +
 src/include/internal/dice.h                   |   4 +
 src/include/internal/tls_wrapper.h            |   2 +
 src/include/internal/verifier.h               |   2 +
 src/include/rats-tls/api.h                    |   8 +-
 src/include/rats-tls/attester.h               |  18 +-
 src/include/rats-tls/cert.h                   |   8 +
 src/include/rats-tls/err.h                    |   1 +
 src/include/rats-tls/log.h                    |   8 +
 src/include/rats-tls/nonce.h                  |   6 +
 src/include/rats-tls/tls_wrapper.h            |   4 +-
 src/include/rats-tls/verifier.h               |  14 +-
 ...tls_wrapper_verify_certificate_extension.c |  99 +++--
 src/tls_wrappers/nulltls/negotiate.c          |   4 +-
 src/tls_wrappers/nulltls/receive.c            |   2 +-
 src/tls_wrappers/nulltls/transmit.c           |   2 +-
 src/tls_wrappers/openssl/CMakeLists.txt       |   1 +
 src/tls_wrappers/openssl/get_nonce.c          |  49 +++
 src/tls_wrappers/openssl/main.c               |   3 +
 src/tls_wrappers/openssl/negotiate.c          |   9 +-
 src/tls_wrappers/openssl/un_negotiate.c       |  38 +-
 src/tls_wrappers/openssl/use_cert.c           |   4 +-
 src/tls_wrappers/openssl/use_privkey.c        |   2 +-
 src/tls_wrappers/openssl/x509_openssl10x.c    |   3 +-
 src/verifiers/CMakeLists.txt                  |   8 +-
 .../internal/rtls_enclave_verifier_select.c   |   2 +-
 src/verifiers/sev-snp/pre_init.c              |  33 +-
 src/verifiers/sev/pre_init.c                  |  11 +-
 src/verifiers/virtcca/CMakeLists.txt          |  39 ++
 src/verifiers/virtcca/cleanup.c               |  20 +
 src/verifiers/virtcca/init.c                  |  23 +
 src/verifiers/virtcca/main.c                  |  33 ++
 src/verifiers/virtcca/pre_init.c              |  15 +
 src/verifiers/virtcca/verify_evidence.c       |  64 +++
 72 files changed, 2430 insertions(+), 241 deletions(-)
 create mode 100644 build.sh
 create mode 100644 samples/virtcca-client/CMakeLists.txt
 create mode 100644 samples/virtcca-client/ima_measure.c
 create mode 100644 samples/virtcca-client/inc/ima_measure.h
 create mode 100644 samples/virtcca-client/rats-client.c
 create mode 100644 samples/virtcca-client/utils/CMakeLists.txt
 create mode 100644 samples/virtcca-server/CMakeLists.txt
 create mode 100644 samples/virtcca-server/rats-server.c
 create mode 100644 src/attesters/virtcca/CMakeLists.txt
 create mode 100644 src/attesters/virtcca/cleanup.c
 create mode 100644 src/attesters/virtcca/collect_evidence.c
 create mode 100644 src/attesters/virtcca/init.c
 create mode 100644 src/attesters/virtcca/main.c
 create mode 100644 src/attesters/virtcca/pre_init.c
 create mode 100644 src/include/rats-tls/nonce.h
 create mode 100644 src/tls_wrappers/openssl/get_nonce.c
 create mode 100644 src/verifiers/virtcca/CMakeLists.txt
 create mode 100644 src/verifiers/virtcca/cleanup.c
 create mode 100644 src/verifiers/virtcca/init.c
 create mode 100644 src/verifiers/virtcca/main.c
 create mode 100644 src/verifiers/virtcca/pre_init.c
 create mode 100644 src/verifiers/virtcca/verify_evidence.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a6585fb..a85336a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,7 +23,7 @@ option(BUILD_FUZZ "Use lib-fuzzer to fuzz the code, default OFF" OFF)
 
 # Define build mode
 set(RATS_TLS_BUILD_MODE "host"
-    CACHE STRING "Select build mode for rats-tls(normal|occlum|sgx)")
+    CACHE STRING "Select build mode for rats-tls(normal|occlum|sgx|virtcca)")
 
 # Print build mode
 message(STATUS "Build Mode: ${RATS_TLS_BUILD_MODE}")
@@ -38,6 +38,7 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
 #  occlum: OCCLUM
 #  sgx: SGX
 #  tdx: TDX
+#  virtcca: VirtCCA
 if(RATS_TLS_BUILD_MODE STREQUAL "host")
     set(HOST 1)
     add_definitions(-DHOST)
@@ -51,12 +52,14 @@ elseif(RATS_TLS_BUILD_MODE STREQUAL "sgx")
     else()
         message(STATUS "Found intel sgx sdk.")
     endif()
-
     set(SGX 1)
     add_definitions(-DSGX)
 elseif(RATS_TLS_BUILD_MODE STREQUAL "tdx")
     set(TDX 1)
     add_definitions(-DTDX)
+elseif(RATS_TLS_BUILD_MODE STREQUAL "virtcca")
+    set(VIRTCCA 1)
+    add_definitions(-DVIRTCCA)
 else()
     message(FATAL_ERROR "Invalid build mode!")
 endif()
@@ -86,6 +89,16 @@ else()
     message(FATAL_ERROR "Invalid build type!")
 endif()
 
+set(RATS_TLS_INSTALL_PATH_DEFAULT "/usr/lib/rats-tls")
+
+# Define install path
+set(RATS_TLS_INSTALL_PATH "${RATS_TLS_INSTALL_PATH_DEFAULT}" CACHE STRING 
+    "Absoluate path to install the .so and .h")
+
+# Define sample path
+set(RATS_TLS_INSTALL_BIN_PATH "/usr/share/rats-tls/samples" CACHE STRING 
+    "Absoluate path to install the sample bin")
+
 # Include custom modules
 include(CustomInstallDirs)
 include(CompilerOptions)
diff --git a/build.sh b/build.sh
new file mode 100644
index 0000000..7885e43
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,309 @@
+#!/bin/bash
+# Copyright Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
+set -e
+
+export ROOT_DIR=$(cd $(dirname "$0"); pwd -P)
+export BUILD_DIR="${ROOT_DIR}"/build
+export OUTPUT_DIR="${ROOT_DIR}"/output
+export SAMPLE_DIR=${OUTPUT_DIR}
+export USR_COMPILER_CC=""
+export BUILD_TYPE=""
+export CLEAN_ENABLED=false
+export BUILD_SAMPLES=off
+export BUILD_FUZZ=off
+export RATS_TLS_BUILD_MODE="virtcca"
+export ARCH="arm64"
+export CROSS_COMPILE
+export CC
+export CXX
+export RATS_TLS_LOG_LEVLE="info"
+
+REMOTE_COMIPLE=OFF
+
+print_help() {
+    echo -e "\nUsage:"
+    echo -e "    build.sh [options]...\n"
+    echo -e "Options:"
+    echo -e "    -v, --usrcompiler compiler for target." 
+    echo -e "        Default value is \"aarch64-linux-gnu-gcc\"\n"
+    echo -e "    -b, --buildtype"
+    echo -e "        Select the build type from debug|prerelease|release. Default value is \"debug\"\n"
+    echo -e "    -c, --clean"
+    echo -e "        Clean all the files from previous build, default false.\n"
+    echo -e "    -s, --sample"
+    echo -e "        Build samples,default false.\n"
+    echo -e "    -f, --fuzz"
+    echo -e "        Build fuzz, default false.\n"
+    echo -e "    -S, --run_server"
+    echo -e "        Run svirtcca-server.\n"
+    echo -e "    -C, --run_client"
+    echo -e "        Run virtcca-client.\n"
+    echo -e "    --sample_client"
+    echo -e "        Run rats-tls-clinet.\n"
+    echo -e "    --sample_server"
+    echo -e "        Run rats-tls-server.\n"
+    echo -e "    -h, --help"
+    echo -e "        Display this help and exit.\n"
+}
+
+run_server() {
+    export LD_LIBRARY_PATH=${OUTPUT_DIR}/lib/rats-tls:$LD_LIBRARY_PATH
+    export RATS_TLS_GLOBAL_LOG_LEVEL=${RATS_TLS_LOG_LEVLE}
+    echo ${LD_LIBRARY_PATH}
+    cd ${SAMPLE_DIR}
+    ./virtcca-server -l ${RATS_TLS_LOG_LEVLE}
+}
+
+run_client() {
+    export LD_LIBRARY_PATH=${OUTPUT_DIR}/lib/rats-tls:$LD_LIBRARY_PATH
+    export RATS_TLS_GLOBAL_LOG_LEVEL=${RATS_TLS_LOG_LEVLE}
+    echo ${LD_LIBRARY_PATH}
+    cd ${SAMPLE_DIR}
+    ./virtcca-client -l ${RATS_TLS_LOG_LEVLE}
+}
+
+sample_client() {
+    export LD_LIBRARY_PATH=${OUTPUT_DIR}/lib/rats-tls:$LD_LIBRARY_PATH
+    export RATS_TLS_GLOBAL_LOG_LEVEL=${RATS_TLS_LOG_LEVLE}
+    echo ${LD_LIBRARY_PATH}
+    cd ${SAMPLE_DIR}
+    ./rats-tls-client -l ${RATS_TLS_LOG_LEVLE}
+}
+
+sample_server() {
+    export LD_LIBRARY_PATH=${OUTPUT_DIR}/lib/rats-tls:$LD_LIBRARY_PATH
+    export RATS_TLS_GLOBAL_LOG_LEVEL=${RATS_TLS_LOG_LEVLE}
+    echo ${LD_LIBRARY_PATH}
+    cd ${SAMPLE_DIR}
+    ./rats-tls-server -l ${RATS_TLS_LOG_LEVLE}
+}
+
+#########################################
+# Parse Input Parameters
+#########################################
+! getopt --test > /dev/null
+if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
+    echo 'getopt is not the enhanced version.'
+    exit 1
+fi
+
+OPTIONS=rb:v:csfSCh
+LONGOPTS=remote,usrcompiler:,buildtype:,clean,sample,fuzz,run_server,run_client,help,sample_client,sample_server
+
+! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "build" -- "$@")
+if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
+    print_help
+    exit 2
+fi
+
+# reset parameters
+eval set -- "$PARSED"
+
+while true; do
+    case "${1}" in
+        -h|--help)
+            print_help
+            exit 0
+            ;;
+        -r|--remote)
+            REMOTE_COMIPLE=ON
+            shift
+            ;;
+        -S|--run_server)
+            run_server
+            exit 0
+            ;;
+        -C|--run_client)
+            run_client
+            exit 0
+            ;;
+        --sample_server)
+            sample_server
+            exit 0
+            ;;
+        --sample_client)
+            sample_client
+            exit 0
+            ;;
+        -b|--buildtype)
+            BUILD_TYPE="${2}"
+            shift 2
+            ;;
+        -v|--usrcompiler)
+            USR_COMPILER_CC="${2}"
+            shift 2
+            ;;
+        -c|--clean)
+            CLEAN_ENABLED="true"
+            shift
+            ;;
+        -s|--sample)
+            BUILD_SAMPLES=on
+            shift
+            ;;
+        -f|--fuzz)
+            BUILD_FUZZ=on
+            shift
+            ;;
+        --)
+            shift
+            break
+            ;;
+        *)
+            echo "Programming error"
+            exit 3
+            ;;
+    esac
+done
+
+#########################################
+# Check Input Parameters
+#########################################
+
+if [[ -z "${CXX}" ]]; then
+    CXX=$(which g++)
+fi
+
+if [[ "${USR_COMPILER_CC}" == "" ]]; then
+    USR_COMPILER_CC=aarch64-linux-gnu-gcc
+elif [ "${USR_COMPILER_CC}" != "aarch64-linux-gnu-gcc" ] && 
+     [ "${USR_COMPILER_CC}" != "gcc" ]; then
+    echo "ERROR: your input compiler is not support: ${USR_COMPILER_CC}"
+    print_help
+    exit 1
+fi
+if [[ -z "${CC}" ]]; then
+    CC="${USR_COMPILER_CC}"
+fi
+
+#set compile item
+if [[ "${USR_COMPILER_CC}" == "gcc" ]]; then
+    CROSS_COMPILE=""
+else
+    CROSS_COMPILE=$(echo "${USR_COMPILER_CC%-*}-")
+fi
+
+if [[ "${BUILD_TYPE}" == "" ]]; then
+    BUILD_TYPE="debug"
+elif [ "${BUILD_TYPE}" != "debug" ] &&
+     [ "${BUILD_TYPE}" != "prerelease" ] && 
+     [ "${BUILD_TYPE}" != "release" ]; then
+     echo "ERROR: your input build type is not support: ${BUILD_TYPE}"
+     print_help
+    exit 1
+fi
+
+echo -e "\nRATS-TLS compiling info:"
+echo -e "user c++ compiler    = ${CXX}"
+echo -e "user c compiler      = ${CC}"
+echo -e "build type           = ${BUILD_TYPE}"
+echo -e "clean enabled        = ${CLEAN_ENABLED}"
+echo -e "building dir         = ${BUILD_DIR}"
+echo -e "output dir           = ${OUTPUT_DIR}\n"
+
+#########################################
+# Compiling Process
+#########################################
+ echo -e "INFO: compiling..."
+
+if [[ "${CLEAN_ENABLED}" == "true" ]]; then
+    [ -n "${BUILD_DIR}" ] && rm -rf "${BUILD_DIR}"
+    [ -n "${OUTPUT_DIR}" ] && rm -rf "${OUTPUT_DIR}"
+fi
+
+mkdir -p "${BUILD_DIR}"
+mkdir -p "${OUTPUT_DIR}"
+
+pushd "${BUILD_DIR}"
+
+cmake -DRATS_TLS_BUILD_MODE=${RATS_TLS_BUILD_MODE} \
+      -DRATS_TLS_BUILD_TYPE=${BUILD_TYPE} \
+      -DBUILD_SAMPLES=${BUILD_SAMPLES} \
+      -DBUILD_FUZZ=${BUILD_FUZZ} \
+      -DSGX_HW=off \
+      -DSGX_LVI_MITIGATION=off \
+      -DRATS_TLS_INSTALL_PATH=${OUTPUT_DIR} \
+      -DRATS_TLS_INSTALL_BIN_PATH=${SAMPLE_DIR} \
+      -DREMOTE_COMIPLE=${REMOTE_COMIPLE} ..
+
+make -C ${BUILD_DIR} install
+popd
+echo "INFO: building rats-tls finished..."
+
+echo "INFO: generating shell script..."
+target_script=${OUTPUT_DIR}/run.sh
+cat > ${target_script} << EOF
+#!/bin/bash
+set -e
+
+export RATS_TLS_LOG_LEVLE="${RATS_TLS_LOG_LEVLE}"
+
+run_server() {
+    export LD_LIBRARY_PATH=/usr/lib/rats-tls:\$LD_LIBRARY_PATH
+    export RATS_TLS_GLOBAL_LOG_LEVEL=\${RATS_TLS_LOG_LEVLE}
+    echo \${LD_LIBRARY_PATH}
+    ./virtcca-server -l \${RATS_TLS_LOG_LEVLE} -I
+}
+
+run_client() {
+    export LD_LIBRARY_PATH=/usr/lib/rats-tls:\$LD_LIBRARY_PATH
+    export RATS_TLS_GLOBAL_LOG_LEVEL=\${RATS_TLS_LOG_LEVLE}
+    echo \${LD_LIBRARY_PATH}
+    ./virtcca-client -l \${RATS_TLS_LOG_LEVLE}
+}
+
+run_server_sample() {
+    export LD_LIBRARY_PATH=/usr/lib/rats-tls:\$LD_LIBRARY_PATH
+    export RATS_TLS_GLOBAL_LOG_LEVEL=\${RATS_TLS_LOG_LEVLE}
+    echo \${LD_LIBRARY_PATH}
+    ./rats-tls-server -l \${RATS_TLS_LOG_LEVLE}
+}
+
+run_client_sample() {
+    export LD_LIBRARY_PATH=/usr/lib/rats-tls:\$LD_LIBRARY_PATH
+    export RATS_TLS_GLOBAL_LOG_LEVEL=\${RATS_TLS_LOG_LEVLE}
+    echo \${LD_LIBRARY_PATH}
+    ./rats-tls-client -l \${RATS_TLS_LOG_LEVLE}
+}
+
+install() {
+    rm -rf /usr/lib/rats-tls
+    rm -rf /usr/local/include/rats-tls
+    mv -f lib/rats-tls /usr/lib/rats-tls
+    mv -f include/rats-tls /usr/local/include/rats-tls
+}
+
+if [ "\$1" == "server" ]
+then
+      run_server
+fi
+
+if [ "\$1" == "client" ]
+then
+      run_client
+fi
+
+if [ "\$1" == "sserver" ]
+then
+      run_server_sample
+fi
+
+if [ "\$1" == "sclient" ]
+then
+      run_client_sample
+fi
+
+if [ "\$1" == "install" ]
+then
+      install
+fi
+EOF
+
+chmod +x ${target_script}
+
+echo "INFO: warpping output..."
+BIN_DIR="${ROOT_DIR}"/bin
+rm -rf ${BIN_DIR}
+mkdir -p ${BIN_DIR}
+pushd "${OUTPUT_DIR}"
+tar -czvf ${BIN_DIR}/rats-tls.tar.gz  *
\ No newline at end of file
diff --git a/cmake/CustomInstallDirs.cmake b/cmake/CustomInstallDirs.cmake
index d6be5bf..83588f1 100644
--- a/cmake/CustomInstallDirs.cmake
+++ b/cmake/CustomInstallDirs.cmake
@@ -1,27 +1,41 @@
-# /usr/local
-set(RATS_TLS_INSTALL_PATH "/usr/local")
-
 # lib/rats_tls
 set(RATS_TLS_INSTALL_LIB_PATH "${RATS_TLS_INSTALL_PATH}/lib/rats-tls")
 
 # rats_tls/crypto-wrappers
 set(RATS_TLS_INSTALL_LIBCW_PATH "${RATS_TLS_INSTALL_LIB_PATH}/crypto-wrappers")
+if(REMOTE_COMIPLE)
+    add_definitions(-DCRYPTO_WRAPPERS_DIR="${RATS_TLS_INSTALL_PATH_DEFAULT}/crypto-wrappers/")
+else()
+    add_definitions(-DCRYPTO_WRAPPERS_DIR="${RATS_TLS_INSTALL_LIBCW_PATH}/")
+endif()
 
 # rats_tls/attesters
 set(RATS_TLS_INSTALL_LIBA_PATH "${RATS_TLS_INSTALL_LIB_PATH}/attesters")
+if(REMOTE_COMIPLE)
+    add_definitions(-DENCLAVE_ATTESTERS_DIR="${RATS_TLS_INSTALL_PATH_DEFAULT}/attesters/")
+else()
+    add_definitions(-DENCLAVE_ATTESTERS_DIR="${RATS_TLS_INSTALL_LIBA_PATH}/")
+endif()
 
 # rats_tls/verifiers
 set(RATS_TLS_INSTALL_LIBV_PATH "${RATS_TLS_INSTALL_LIB_PATH}/verifiers")
+if(REMOTE_COMIPLE)
+    add_definitions(-DENCLAVE_VERIFIERS_DIR="${RATS_TLS_INSTALL_PATH_DEFAULT}/verifiers/")
+else()
+    add_definitions(-DENCLAVE_VERIFIERS_DIR="${RATS_TLS_INSTALL_LIBV_PATH}/")
+endif()
 
 # rats_tls/tls-wrappers
 set(RATS_TLS_INSTALL_LIBTW_PATH "${RATS_TLS_INSTALL_LIB_PATH}/tls-wrappers")
+if(REMOTE_COMIPLE)
+    add_definitions(-DTLS_WRAPPERS_DIR="${RATS_TLS_INSTALL_PATH_DEFAULT}/tls-wrappers/")
+else()
+    add_definitions(-DTLS_WRAPPERS_DIR="${RATS_TLS_INSTALL_LIBTW_PATH}/")
+endif()
 
 # include/rats_tls
 set(RATS_TLS_INSTALL_INCLUDE_PATH "${RATS_TLS_INSTALL_PATH}/include/rats-tls")
 
-# rats_tls/sample
-set(RATS_TLS_INSTALL_BIN_PATH "/usr/share/rats-tls/samples")
-
 # sgx sdk
 if(EXISTS $ENV{SGX_SDK})
     set(SGXSDK_INSTALL_PATH "$ENV{SGX_SDK}")
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt
index c77319e..dca3333 100644
--- a/samples/CMakeLists.txt
+++ b/samples/CMakeLists.txt
@@ -1,5 +1,7 @@
 add_subdirectory(rats-tls-client)
 add_subdirectory(rats-tls-server)
+add_subdirectory(virtcca-server)
+add_subdirectory(virtcca-client)
 if(SGX)
     add_subdirectory(sgx-stub-enclave)
 endif()
diff --git a/samples/rats-tls-client/CMakeLists.txt b/samples/rats-tls-client/CMakeLists.txt
index 4fd68a4..bfbbaff 100644
--- a/samples/rats-tls-client/CMakeLists.txt
+++ b/samples/rats-tls-client/CMakeLists.txt
@@ -67,4 +67,4 @@ else()
 endif()
 
 install(TARGETS ${PROJECT_NAME}
-	DESTINATION /usr/share/rats-tls/samples)
+	DESTINATION ${RATS_TLS_INSTALL_BIN_PATH})
diff --git a/samples/rats-tls-server/CMakeLists.txt b/samples/rats-tls-server/CMakeLists.txt
index 1e3d0b9..c70293d 100644
--- a/samples/rats-tls-server/CMakeLists.txt
+++ b/samples/rats-tls-server/CMakeLists.txt
@@ -68,4 +68,4 @@ else()
 endif()
 
 install(TARGETS ${PROJECT_NAME}
-	DESTINATION /usr/share/rats-tls/samples)
+	DESTINATION ${RATS_TLS_INSTALL_BIN_PATH})
diff --git a/samples/sgx-stub-enclave/CMakeLists.txt b/samples/sgx-stub-enclave/CMakeLists.txt
index 8b1293e..1e9875b 100644
--- a/samples/sgx-stub-enclave/CMakeLists.txt
+++ b/samples/sgx-stub-enclave/CMakeLists.txt
@@ -76,4 +76,4 @@ enclave_sign(sgx_stub_enclave KEY sgx_stub_enclave.pem CONFIG sgx_stub_enclave.x
 add_dependencies(sgx_stub_enclave rats_tls)
 
 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sgx_stub_enclave.signed.so
-        DESTINATION /usr/share/rats-tls/samples)
+        DESTINATION ${RATS_TLS_INSTALL_BIN_PATH})
diff --git a/samples/sgx-stub-enclave/sgx_stub_ecall.c b/samples/sgx-stub-enclave/sgx_stub_ecall.c
index 4d05bd5..9a6f20e 100644
--- a/samples/sgx-stub-enclave/sgx_stub_ecall.c
+++ b/samples/sgx-stub-enclave/sgx_stub_ecall.c
@@ -127,7 +127,7 @@ int ecall_rtls_server_startup(rats_tls_log_level_t log_level, char *attester_typ
 	uint32_t addrlen_in = sizeof(c_addr);
 	uint32_t addrlen_out;
 	while (1) {
-		RTLS_INFO("Waiting for a connection from client ...\n");
+		RTLS_INFO("Waiting for a connection ...\n");
 
 		int64_t connd;
 		sgx_status = ocall_accept(&connd, sockfd, &c_addr, addrlen_in, &addrlen_out);
@@ -255,7 +255,7 @@ int ecall_rtls_client_startup(rats_tls_log_level_t log_level, char *attester_typ
 	if (verdictd)
 		msg = "{ \"command\": \"echo\", \"data\": \"Hello and welcome to RATS-TLS!\\n\" }";
 	else
-		msg = "\033[94mHello and welcome to RATS-TLS!\033[0m\n";
+		msg = "Hello and welcome to RATS-TLS!\n";
 
 	size_t len = strlen(msg);
 	ret = rats_tls_transmit(handle, (void *)msg, &len);
@@ -299,7 +299,7 @@ int ecall_rtls_client_startup(rats_tls_log_level_t log_level, char *attester_typ
 	}
 
 	if (verdictd)
-		msg = "\033[94mHello and welcome to RATS-TLS!\033[0m\n";
+		msg = "Hello and welcome to RATS-TLS!\n";
 
 	/* Sanity check whether the response is expected */
 	if (strcmp(msg, buf)) {
diff --git a/samples/virtcca-client/CMakeLists.txt b/samples/virtcca-client/CMakeLists.txt
new file mode 100644
index 0000000..6e6b036
--- /dev/null
+++ b/samples/virtcca-client/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Project name
+project(virtcca-client)
+
+# add_subdirectory(t_cose)
+add_subdirectory(utils)
+
+set(CMAKE_C_FLAGS "-fPIE ${CMAKE_C_FLAGS}")
+set(INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../../src/include
+                    ${CMAKE_CURRENT_SOURCE_DIR}/../../src/include/edl
+                    ${CMAKE_CURRENT_SOURCE_DIR}/../../src/include/rats-tls
+                    ${RATS_TLS_INSTALL_INCLUDE_PATH}
+                    ${RATS_TLS_INSTALL_INCLUDE_PATH}/edl
+                    ${CMAKE_CURRENT_SOURCE_DIR}/inc
+                    ${CMAKE_CURRENT_SOURCE_DIR}/t_cose/inc
+                    )
+set(LIBRARY_DIRS ${RATS_TLS_INSTALL_LIB_PATH})
+
+
+include_directories(${INCLUDE_DIRS})
+link_directories(${LIBRARY_DIRS})
+
+# Set source file
+set(SOURCES rats-client.c token_parse.c token_validate.c ima_measure.c)
+
+# Generate bin file
+add_executable(${PROJECT_NAME} ${SOURCES})
+target_link_libraries(${PROJECT_NAME} rats_tls utils t_cose qcbor crypto m)
+
+install(TARGETS ${PROJECT_NAME}
+	    DESTINATION ${RATS_TLS_INSTALL_BIN_PATH})
+
+
+# Install aik_cert.pem to output directory when in Debug mode
+if(DEBUG)
+    set(EXAMPLE_AIK_CERT "${CMAKE_CURRENT_SOURCE_DIR}/aik_cert.pem")
+    install(FILES ${EXAMPLE_AIK_CERT}
+            DESTINATION ${RATS_TLS_INSTALL_BIN_PATH})
+    message(STATUS "Copy ${EXAMPLE_AIK_CERT} to ${RATS_TLS_INSTALL_BIN_PATH} when installing")
+endif()
diff --git a/samples/virtcca-client/ima_measure.c b/samples/virtcca-client/ima_measure.c
new file mode 100644
index 0000000..5b0be69
--- /dev/null
+++ b/samples/virtcca-client/ima_measure.c
@@ -0,0 +1,414 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rats-tls/api.h>
+#include <rats-tls/log.h>
+#include <rats-tls/claim.h>
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <ima_measure.h>
+
+/* static int verify_sig; */
+/* static unsigned int no_sigs, unknown_keys, invalid_sigs; */
+
+static u_int8_t zero[SHA_DIGEST_LENGTH];
+static u_int8_t fox[SHA_DIGEST_LENGTH];
+static u_int8_t extend[SHA256_DIGEST_LENGTH];
+
+static int display_digest(u_int8_t * digest, u_int32_t digestlen)
+{
+	int i;
+
+	for (i = 0; i < digestlen; i++) {
+		printf("%02x", (*(digest + i) & 0xff));
+	}
+	return 0;
+}
+
+static int ima_eventdigest_parse(u_int8_t * buffer, u_int32_t buflen)
+{
+	return display_digest(buffer, SHA_DIGEST_LENGTH);
+}
+
+static int ima_eventdigest_ng_parse(u_int8_t * buffer, u_int32_t buflen)
+{
+	char hash_algo[CRYPTO_MAX_ALG_NAME + 1] = { 0 };
+	int algo_len = strlen((char *)buffer) - 1; /* format: algo + ':' + '\0' */
+	const EVP_MD *md;
+	int digest_len;
+
+	if (algo_len > CRYPTO_MAX_ALG_NAME) {
+		printf("Hash algorithm name too long\n");
+		return ERROR_ENTRY_PARSING;
+	}
+
+	printf("%s", buffer);
+
+	memcpy(hash_algo, buffer, algo_len);
+	md = EVP_get_digestbyname(hash_algo);
+	if (md == NULL) {
+		printf("Unknown hash algorithm '%s'\n", hash_algo);
+		return ERROR_ENTRY_PARSING;
+	}
+
+	digest_len = EVP_MD_size(md);
+
+	if (algo_len + 2 + digest_len != buflen) {
+		printf("Field length mismatch, current: %d, expected: %d\n",
+		       algo_len + 2 + digest_len, buflen);
+		return ERROR_ENTRY_PARSING;
+	}
+
+	return display_digest(buffer + algo_len + 2, digest_len);
+}
+
+static int ima_parse_string(u_int8_t * buffer, u_int32_t buflen)
+{
+	char *str;
+
+	/* some callers include the terminating null in the
+ 	 * buflen, others don't (eg. 'd').
+ 	 */
+	str = calloc(buflen + 1, sizeof(u_int8_t));
+	if (str == NULL) {
+		printf("Out of memory\n");
+		return -ENOMEM;
+	}
+
+	memcpy(str, buffer, buflen);
+	printf("%s", str);
+	free(str);
+	return 0;
+}
+
+static int ima_eventname_parse(u_int8_t * buffer, u_int32_t buflen)
+{
+	if (buflen > TCG_EVENT_NAME_LEN_MAX + 1) {
+		printf("Event name too long\n");
+		return -1;
+	}
+
+	return ima_parse_string(buffer, buflen);
+}
+
+static int ima_eventname_ng_parse(u_int8_t * buffer, u_int32_t buflen)
+{
+	return ima_parse_string(buffer, buflen);
+}
+
+static int ima_eventsig_parse(u_int8_t * buffer, u_int32_t buflen)
+{
+	return display_digest(buffer, buflen);
+}
+
+/* IMA template field definition */
+struct ima_template_field {
+	const char field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN];
+	int (*field_parse) (u_int8_t * buffer, u_int32_t buflen);
+};
+
+/* IMA template descriptor definition */
+struct ima_template_desc {
+	char *name;
+	char *fmt;
+	int num_fields;
+	struct ima_template_field **fields;
+};
+
+static struct ima_template_desc defined_templates[] = {
+	{.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},
+	{.name = "ima-ng",.fmt = "d-ng|n-ng"},
+	{.name = "ima-sig",.fmt = "d-ng|n-ng|sig"},
+};
+
+static struct ima_template_field supported_fields[] = {
+	{.field_id = "d",.field_parse = ima_eventdigest_parse},
+	{.field_id = "n",.field_parse = ima_eventname_parse},
+	{.field_id = "d-ng",.field_parse = ima_eventdigest_ng_parse},
+	{.field_id = "n-ng",.field_parse = ima_eventname_ng_parse},
+	{.field_id = "sig",.field_parse = ima_eventsig_parse},
+};
+
+struct event {
+	struct {
+		u_int32_t pcr;
+		u_int8_t digest[SHA_DIGEST_LENGTH];
+		u_int32_t name_len;
+	} header;
+	char name[TCG_EVENT_NAME_LEN_MAX + 1];
+	struct ima_template_desc *template_desc; /* template descriptor */
+	u_int32_t template_data_len;
+	u_int8_t *template_data;	/* template related data */
+};
+
+static int parse_template_data(struct event *template)
+{
+	int offset = 0, result = 0;
+	int i, j, is_ima_template;
+	char *template_fmt, *template_fmt_ptr, *f;
+	u_int32_t digest_len;
+	u_int8_t *digest;
+
+	is_ima_template = strcmp(template->name, "ima") == 0 ? 1 : 0;
+	template->template_desc = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(defined_templates); i++) {
+		if (strcmp(template->name,
+			defined_templates[i].name) == 0) {
+			template->template_desc = defined_templates + i;
+			break;
+		}
+	}
+
+	if (template->template_desc == NULL) {
+		i = ARRAY_SIZE(defined_templates) - 1;
+		template->template_desc = defined_templates + i;
+		template->template_desc->fmt = template->name;
+	}
+
+	template_fmt = strdup(template->template_desc->fmt);
+	if (template_fmt == NULL) {
+		printf("Out of memory\n");
+		return -ENOMEM;
+	}
+
+	template_fmt_ptr = template_fmt;
+	for (i = 0; (f = strsep(&template_fmt_ptr, "|")) != NULL; i++) {
+		struct ima_template_field *field = NULL;
+		u_int32_t field_len = 0;
+
+		for (j = 0; j < ARRAY_SIZE(supported_fields); j++) {
+			if (!strcmp(f, supported_fields[j].field_id)) {
+				field = supported_fields + j;
+				break;
+			}
+		}
+
+		if (field == NULL) {
+			result = ERROR_FIELD_NOT_FOUND;
+			printf("Field '%s' not supported\n", f);
+			goto out;
+		}
+
+		if (is_ima_template && strcmp(f, "d") == 0)
+			field_len = SHA_DIGEST_LENGTH;
+		else if (is_ima_template && strcmp(f, "n") == 0)
+			field_len = strlen(template->template_data + offset);
+		else {
+			memcpy(&field_len, template->template_data + offset,
+				 sizeof(u_int32_t));
+			offset += sizeof(u_int32_t);
+		}
+		result = field->field_parse(template->template_data + offset,
+					    field_len);
+		if (result) {
+			printf("Parsing of '%s' field failed, result: %d\n",
+			       f, result);
+			goto out;
+		} 
+
+		/* ToDo: add verifiy ima-sig template */
+
+		offset += field_len;
+		printf(" ");
+	}
+out:
+	free(template_fmt);
+	return result;
+}
+
+static int read_template_data(struct event *template, FILE *fp)
+{
+	int len, is_ima_template;
+	int byte_read;
+
+	is_ima_template = strcmp(template->name, "ima") == 0 ? 1 : 0;
+	if (!is_ima_template) {
+		byte_read = fread(&template->template_data_len, sizeof(u_int32_t), 1, fp);
+		len = template->template_data_len;
+	} else {
+		template->template_data_len = SHA_DIGEST_LENGTH +
+		    TCG_EVENT_NAME_LEN_MAX + 1;
+		/*
+		 * Read the digest only as the event name length
+		 * is not known in advance.
+		 */
+		len = SHA_DIGEST_LENGTH;
+	}
+
+	template->template_data = calloc(template->template_data_len,
+					 sizeof(u_int8_t));
+	if (template->template_data == NULL) {
+		printf("ERROR: out of memory\n");
+		return -ENOMEM;
+	}
+
+	byte_read = fread(template->template_data, len, 1, fp);
+	if (is_ima_template) {	/* finish 'ima' template data read */
+		u_int32_t field_len;
+
+		byte_read = fread(&field_len, sizeof(u_int32_t), 1, fp);
+		byte_read = fread(template->template_data + SHA_DIGEST_LENGTH,
+		      field_len, 1, fp);
+	}
+	return 0;
+}
+
+/*
+ * Calculate the sha1 hash of data
+ */
+static void calc_digest(u_int8_t * digest, int len, void *data)
+{
+	SHA_CTX c;
+
+	/* Calc template hash for an ima entry */
+	memset(digest, 0, sizeof(*digest));
+	SHA1_Init(&c);
+	SHA1_Update(&c, data, len);
+	SHA1_Final(digest, &c);
+}
+
+static int verify_template_hash(struct event *template)
+{
+	int rc;
+
+	rc = memcmp(fox, template->header.digest, sizeof(fox));
+	if (rc != 0) {
+		u_int8_t digest[SHA_DIGEST_LENGTH];
+		memset(digest, 0, sizeof(digest));
+		calc_digest(digest, template->template_data_len,
+			    template->template_data);
+		rc = memcmp(digest, template->header.digest, sizeof(digest));
+		if (rc != 0)
+			printf("- %s\n", "failed");
+	}
+	return rc != 0 ? 1 : 0 ;
+}
+
+/*
+ * calculate the SHA1 aggregate-pcr value based on the
+ * IMA runtime binary measurements.
+ *
+ * --validate: forces validation of the aggregrate pcr value
+ * 	     for an invalidated PCR. Replace all entries in the
+ * 	     runtime binary measurement list with 0x00 hash values,
+ * 	     which indicate the PCR was invalidated, either for
+ * 	     "a time of measure, time of use"(ToMToU) error, or a
+ *	     file open for read was already open for write, with
+ * 	     0xFF's hash value, when calculating the aggregate
+ *	     pcr value.
+ *
+ * --verify: for all IMA template entries in the runtime binary
+ * 	     measurement list, calculate the template hash value
+ * 	     and compare it with the actual template hash value.
+ * 	     
+ * 	     For records with a signature, verify the file data
+ * 	     hash against the file signature.
+ *
+ *	     Return the number of incorrect hash measurements
+ *	     and signatures.
+ *
+ * template info:  list #, PCR-register #, template hash, template name
+ *	IMA info:  IMA hash, filename hint
+ *
+ * Ouput: displays the aggregate-pcr value
+ * Return code: if verification enabled, returns number of verification
+ * 		errors.
+ */
+int ima_measure(void *data, size_t datalen, int validate, int verify)
+{
+	int ret;
+	FILE *fp;
+	struct event template;
+	u_int8_t pcr[SHA256_DIGEST_LENGTH];
+	int i, count = 0;
+	int hash_failed = 0;
+	size_t byte_read;
+	
+	fp = fopen(IMA_MEASUREMENTS_PATH, "r");
+	if (!fp) {
+		printf("fn: %s\n", IMA_MEASUREMENTS_PATH);
+		perror("Unable to open file\n");
+		return 1;
+	}
+	memset(pcr, 0, SHA256_DIGEST_LENGTH);	/* initial PCR content 0..0 */
+	memset(zero, 0, SHA_DIGEST_LENGTH);
+	memset(fox, 0xff, SHA_DIGEST_LENGTH);
+
+	printf("### PCR HASH                                  "
+		   "TEMPLATE-NAME\n");
+	while (fread(&template.header, sizeof(template.header), 1, fp)) {
+		SHA256_CTX c;
+
+		/* Extend simulated PCR with new template digest */
+		SHA256_Init(&c);
+		SHA256_Update(&c, pcr, SHA256_DIGEST_LENGTH);
+		if (validate) {
+			if (memcmp(template.header.digest, zero, SHA_DIGEST_LENGTH) == 0)
+				memset(template.header.digest, 0xFF, SHA_DIGEST_LENGTH);
+		}
+		
+		memset(extend, 0, SHA256_DIGEST_LENGTH);
+		memcpy(extend, template.header.digest, SHA_DIGEST_LENGTH);
+
+		SHA256_Update(&c, extend, SHA256_DIGEST_LENGTH);
+		SHA256_Final(pcr, &c);
+
+		OpenSSL_add_all_digests();
+
+		printf("%3d %03u ", count++, template.header.pcr);
+		display_digest(template.header.digest, SHA_DIGEST_LENGTH);
+		if (template.header.name_len > TCG_EVENT_NAME_LEN_MAX) {
+			printf("%d ERROR: event name too long!\n",
+			       template.header.name_len);
+			fclose(fp);
+			EVP_cleanup();
+			return 1;
+		}
+		memset(template.name, 0, sizeof(template.name));
+		byte_read = fread(template.name, template.header.name_len, 1, fp);
+		printf(" %s ", template.name);
+
+		if (read_template_data(&template, fp) < 0) {
+			RTLS_ERR("Reading of measurement entry failed\n");
+			break;
+		}
+
+		if (parse_template_data(&template) != 0) {
+			RTLS_ERR("Parsing of measurement entry failed\n");
+		}
+
+		if (verify) {
+			if (verify_template_hash(&template) != 0) {
+				hash_failed++;
+			}
+		}
+		printf("\n");
+		free(template.template_data);
+	}
+	fclose(fp);
+	EVP_cleanup();
+
+	printf("PCRAggr (re-calculated): ");
+	display_digest(pcr, SHA256_DIGEST_LENGTH);
+	printf("\n");
+
+	if (verify)	{
+		RTLS_INFO("Template hash verification: %s, failures is %d \n", !hash_failed ? "Success" : "Failed", hash_failed);
+	}
+
+	if (validate) {
+		ret = memcmp(pcr, data, datalen);
+		RTLS_INFO("Verifying if REM of cVM token matches reference value: %s \n",
+			(ret == 0) ? "Success" : "Failed");
+		if (ret != 0) {
+			return 1;
+		}
+	}
+
+	return 0;	
+}
\ No newline at end of file
diff --git a/samples/virtcca-client/inc/ima_measure.h b/samples/virtcca-client/inc/ima_measure.h
new file mode 100644
index 0000000..aeb5064
--- /dev/null
+++ b/samples/virtcca-client/inc/ima_measure.h
@@ -0,0 +1,17 @@
+#define TCG_EVENT_NAME_LEN_MAX	255
+#define IMA_TEMPLATE_FIELD_ID_MAX_LEN	16
+#define IMA_TEMPLATE_NUM_FIELDS_MAX	15
+#define CRYPTO_MAX_ALG_NAME 64
+
+#define IMA_TEMPLATE_IMA_NAME "ima"
+#define IMA_TEMPLATE_IMA_FMT "d|n"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+
+#define ERROR_ENTRY_PARSING 1
+#define ERROR_FIELD_NOT_FOUND 2
+
+#define IMA_MEASUREMENTS_PATH "binary_runtime_measurements"
+
+
+int ima_measure(void *data, size_t datalen, int validate, int verify);
diff --git a/samples/virtcca-client/rats-client.c b/samples/virtcca-client/rats-client.c
new file mode 100644
index 0000000..0588464
--- /dev/null
+++ b/samples/virtcca-client/rats-client.c
@@ -0,0 +1,309 @@
+/* Copyright (c) 2021 Intel Corporation
+ * Copyright (c) 2020-2021 Alibaba Cloud
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <getopt.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <rats-tls/api.h>
+#include <rats-tls/log.h>
+#include <rats-tls/claim.h>
+#include "token_parse.h"
+#include "token_validate.h"
+#include "utils.h"
+#include "ima_measure.h"
+
+#define DEFAULT_PORT 1234
+#define DEFAULT_IP   "127.0.0.1"
+#define TOKEN "ATTESTATION_PASS"
+
+#define SHA256_SIZE 32
+#define SHA512_SIZE 64
+#define MAX_MEASUREMENT_SIZE SHA512_SIZE
+
+static uint8_t rim_ref[MAX_MEASUREMENT_SIZE];
+static size_t rim_ref_size = MAX_MEASUREMENT_SIZE;
+
+int user_callback(void *args)
+{
+	rtls_evidence_t *ev = (rtls_evidence_t *)args;
+	bool ret = true;
+	FILE *fp;
+	size_t byte_write;
+	int validate = 1;
+	int verify = 1;
+
+	cca_token_t token = {0};
+	cca_token_buf_t cca_token_buf = {0};
+	memcpy(&cca_token_buf, ev->cca.evidence, ev->cca.evidence_sz);
+	int i;
+	ret = parse_cca_attestation_token(&token, cca_token_buf.buf, cca_token_buf.buf_size);
+    if (ret != VIRTCCA_SUCCESS) {
+        RTLS_ERR("failed to parse virtcca token\n");
+        return ENCLAVE_VERIFIER_ERR_CBOR;
+    }
+
+	cert_info_t cert_info;
+	/* TODO: Read config files that includes certs path, rim, etc. */
+	strcpy(cert_info.cert_path_prefix, DEFAULT_CERT_PEM_PREFIX);
+    strcpy(cert_info.root_cert_filename, DEFAULT_ROOT_CERT_PEM_FILENAME);
+    strcpy(cert_info.sub_cert_filename, DEFAULT_SUB_CERT_PEM_FILENAME);
+    strcpy(cert_info.aik_cert_filename, DEFAULT_AIK_CERT_PEM_FILENAME);
+    strcpy(cert_info.root_cert_url, DEFAULT_ROOT_CERT_URL);
+    strcpy(cert_info.sub_cert_url, DEFAULT_SUB_CERT_URL);
+
+	ret = verify_cca_token_signatures(&cert_info,
+                                token.cvm_cose,
+                                token.cvm_token.pub_key,
+                                token.cvm_token.pub_key_hash_algo_id);
+	if (!ret) {
+        return false;
+    }
+
+	if (token.cvm_token.rim.len != rim_ref_size || 
+		memcmp(rim_ref, token.cvm_token.rim.ptr, token.cvm_token.rim.len)) {
+        printf("Verifying if RIM of cVM token matches reference value: Failed \n");
+		return false;
+    }
+
+	printf("verify_callback called, claims %p, claims_size %zu, args %p\n", ev->custom_claims,
+	       ev->custom_claims_length, args);
+	for (size_t i = 0; i < ev->custom_claims_length; ++i) {
+		printf("custom_claims[%zu] -> name: '%s' value_size: %zu value: '%.*s'\n", i,
+		       ev->custom_claims[i].name, ev->custom_claims[i].value_size,
+		       (int)ev->custom_claims[i].value_size, ev->custom_claims[i].value);
+		ret = (strcmp(ev->custom_claims[i].name, "ima") == 0);
+		if (ret) {
+			fp = fopen(IMA_MEASUREMENTS_PATH, "w");
+			byte_write = fwrite(ev->custom_claims[i].value, ev->custom_claims[i].value_size, 1, fp);
+			fclose(fp);
+			if (ima_measure((void *) token.cvm_token.rem[0].ptr, token.cvm_token.rem[0].len, validate, verify) != 0) {
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+int rats_tls_client_startup(rats_tls_log_level_t log_level, char *attester_type,
+			    char *verifier_type, char *tls_type, char *crypto_type, bool mutual,
+			    bool provide_endorsements, char *ip, int port)
+{
+	rats_tls_conf_t conf;
+
+	memset(&conf, 0, sizeof(conf));
+	conf.log_level = log_level;
+	strcpy(conf.attester_type, attester_type);
+	strcpy(conf.verifier_type, verifier_type);
+	strcpy(conf.tls_type, tls_type);
+	strcpy(conf.crypto_type, crypto_type);
+	conf.cert_algo = RATS_TLS_CERT_ALGO_DEFAULT;
+	if (mutual)
+		conf.flags |= RATS_TLS_CONF_FLAGS_MUTUAL;
+	if (provide_endorsements)
+		conf.flags |= RATS_TLS_CONF_FLAGS_PROVIDE_ENDORSEMENTS;
+
+	/* Create a socket that uses an internet IPv4 address,
+	 * Sets the socket to be stream based (TCP),
+	 * 0 means choose the default protocol.
+	 */
+	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+	if (sockfd < 0) {
+		RTLS_ERR("failed to call socket()\n");
+		return -1;
+	}
+
+	struct sockaddr_in s_addr;
+	memset(&s_addr, 0, sizeof(s_addr));
+	s_addr.sin_family = AF_INET;
+	s_addr.sin_port = htons(port);
+
+	/* Get the server IPv4 address from the command line call */
+	if (inet_pton(AF_INET, ip, &s_addr.sin_addr) != 1) {
+		RTLS_ERR("invalid server address\n");
+		return -1;
+	}
+
+	/* Connect to the server */
+	if (connect(sockfd, (struct sockaddr *)&s_addr, sizeof(s_addr)) == -1) {
+		RTLS_ERR("failed to call connect()\n");
+		return -1;
+	}
+
+	rats_tls_handle handle;
+	rats_tls_err_t ret = rats_tls_init(&conf, &handle);
+	if (ret != RATS_TLS_ERR_NONE) {
+		RTLS_ERR("Failed to initialize rats tls %#x\n", ret);
+		return -1;
+	}
+
+	ret = rats_tls_set_verification_callback(&handle, user_callback);
+	if (ret != RATS_TLS_ERR_NONE) {
+		RTLS_ERR("Failed to set verification callback %#x\n", ret);
+		return -1;
+	}
+
+	ret = rats_tls_negotiate(handle, sockfd);
+	if (ret != RATS_TLS_ERR_NONE) {
+		RTLS_ERR("Failed to negotiate %#x\n", ret);
+		goto err;
+	}
+
+	const char *msg = TOKEN;
+
+	size_t len = strlen(msg);
+	ret = rats_tls_transmit(handle, (void *)msg, &len);
+	if (ret != RATS_TLS_ERR_NONE || len != strlen(msg)) {
+		RTLS_ERR("Failed to transmit %#x\n", ret);
+		goto err;
+	}
+
+	char buf[1024];
+	len = sizeof(buf);
+	ret = rats_tls_receive(handle, buf, &len);
+	if (ret != RATS_TLS_ERR_NONE) {
+		RTLS_ERR("Failed to receive %#x\n", ret);
+		goto err;
+	}
+
+	if (len >= sizeof(buf))
+		len = sizeof(buf) - 1;
+	buf[len] = '\0';
+
+	/* Server not running in SGX Enlcave will only send hello message to client */
+	printf("Sent to Server: %s\n", msg);
+	printf("Received from Server: %s\n", buf);
+
+	shutdown(sockfd, SHUT_RDWR);
+	close(sockfd);
+	ret = rats_tls_cleanup(handle);
+	if (ret != RATS_TLS_ERR_NONE)
+		RTLS_ERR("Failed to cleanup %#x\n", ret);
+
+	return ret;
+
+err:
+	/* Ignore the error code of cleanup in order to return the prepositional error */
+	shutdown(sockfd, SHUT_RDWR);
+	close(sockfd);
+	rats_tls_cleanup(handle);
+
+	return -1;
+}
+
+int main(int argc, char **argv)
+{
+	char *const short_options = "a:v:t:c:mel:i:p:r:h";
+	// clang-format off
+	struct option long_options[] = {
+		{ "attester", required_argument, NULL, 'a' },
+		{ "verifier", required_argument, NULL, 'v' },
+		{ "tls", required_argument, NULL, 't' },
+		{ "crypto", required_argument, NULL, 'c' },
+		{ "mutual", no_argument, NULL, 'm' },
+		{ "endorsements", no_argument, NULL, 'e' },
+		{ "log-level", required_argument, NULL, 'l' },
+		{ "ip", required_argument, NULL, 'i' },
+		{ "port", required_argument, NULL, 'p' },
+		{ "rim", required_argument, NULL, 'r' },
+		{ "help", no_argument, NULL, 'h' },
+		{ 0, 0, 0, 0 }
+	};
+	// clang-format on
+
+	char *attester_type = "";
+	char *verifier_type = "";
+	char *tls_type = "";
+	char *crypto_type = "";
+	bool mutual = false;
+	bool provide_endorsements = false;
+	rats_tls_log_level_t log_level = RATS_TLS_LOG_LEVEL_INFO;
+	char *srv_ip = DEFAULT_IP;
+	int port = DEFAULT_PORT;
+	char *rim = "";
+	int opt;
+
+	do {
+		opt = getopt_long(argc, argv, short_options, long_options, NULL);
+		switch (opt) {
+		case 'a':
+			attester_type = optarg;
+			break;
+		case 'v':
+			verifier_type = optarg;
+			break;
+		case 't':
+			tls_type = optarg;
+			break;
+		case 'c':
+			crypto_type = optarg;
+			break;
+		case 'm':
+			mutual = true;
+			break;
+		case 'e':
+			provide_endorsements = true;
+			break;
+		case 'l':
+			if (!strcasecmp(optarg, "debug"))
+				log_level = RATS_TLS_LOG_LEVEL_DEBUG;
+			else if (!strcasecmp(optarg, "info"))
+				log_level = RATS_TLS_LOG_LEVEL_INFO;
+			else if (!strcasecmp(optarg, "warn"))
+				log_level = RATS_TLS_LOG_LEVEL_WARN;
+			else if (!strcasecmp(optarg, "error"))
+				log_level = RATS_TLS_LOG_LEVEL_ERROR;
+			else if (!strcasecmp(optarg, "fatal"))
+				log_level = RATS_TLS_LOG_LEVEL_FATAL;
+			else if (!strcasecmp(optarg, "off"))
+				log_level = RATS_TLS_LOG_LEVEL_NONE;
+			break;
+		case 'i':
+			srv_ip = optarg;
+			break;
+		case 'p':
+			port = atoi(optarg);
+			break;
+		case 'r':
+			rim = optarg;
+			if (hex_to_bytes(rim, strlen(rim), rim_ref, &rim_ref_size) != 0) {
+				exit(1);
+			}
+			break;
+		case -1:
+			break;
+		case 'h':
+			puts("    Usage:\n\n"
+			     "        rats-tls-client <options> [arguments]\n\n"
+			     "    Options:\n\n"
+			     "        --attester/-a value   set the type of quote attester\n"
+			     "        --verifier/-v value   set the type of quote verifier\n"
+			     "        --tls/-t value        set the type of tls wrapper\n"
+			     "        --crypto/-c value     set the type of crypto wrapper\n"
+			     "        --mutual/-m           set to enable mutual attestation\n"
+			     "        --endorsements/-e     set to let attester provide endorsements\n"
+			     "        --log-level/-l        set the log level\n"
+			     "        --ip/-i               set the listening ip address\n"
+			     "        --port/-p             set the listening tcp port\n"
+			     "        --rim/-r              set the initial measurement of cVM\n"
+			     "        --help/-h             show the usage\n");
+			exit(1);
+		default:
+			exit(1);
+		}
+	} while (opt != -1);
+
+	global_log_level = log_level;
+
+	return rats_tls_client_startup(log_level, attester_type, verifier_type, tls_type,
+				       crypto_type, mutual, provide_endorsements, srv_ip, port);
+}
diff --git a/samples/virtcca-client/utils/CMakeLists.txt b/samples/virtcca-client/utils/CMakeLists.txt
new file mode 100644
index 0000000..84d6b47
--- /dev/null
+++ b/samples/virtcca-client/utils/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.12)
+project(utils
+        DESCRIPTION "utils"
+        LANGUAGES C)
+ 
+# Built-in CMake options
+set(BUILD_SHARED_LIBS OFF CACHE BOOL "Create shared instead of static libraries")
+
+if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+    message(STATUS "No build type selected, defaulting to Release")
+    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
+endif()
+
+set(UTILS_SRC_COMMON
+    src/utils.c
+)
+
+add_library(${PROJECT_NAME} STATIC ${UTILS_SRC_COMMON})
+target_include_directories(${PROJECT_NAME} PUBLIC inc PRIVATE src)
\ No newline at end of file
diff --git a/samples/virtcca-server/CMakeLists.txt b/samples/virtcca-server/CMakeLists.txt
new file mode 100644
index 0000000..12b2ede
--- /dev/null
+++ b/samples/virtcca-server/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Project name
+project(virtcca-server)
+
+set(CMAKE_C_FLAGS "-fPIE ${CMAKE_C_FLAGS}")
+
+set(INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../../src/include
+                    ${CMAKE_CURRENT_SOURCE_DIR}/../../src/include/edl
+                    ${CMAKE_CURRENT_SOURCE_DIR}/../../src/include/rats-tls
+                    ${RATS_TLS_INSTALL_INCLUDE_PATH}
+                    ${RATS_TLS_INSTALL_INCLUDE_PATH}/edl
+                    )
+set(LIBRARY_DIRS ${RATS_TLS_INSTALL_LIB_PATH})
+
+include_directories(${INCLUDE_DIRS})
+link_directories(${LIBRARY_DIRS})
+
+# Set source file
+set(SOURCES rats-server.c)
+
+# Generate bin file
+add_executable(${PROJECT_NAME} ${SOURCES})
+target_link_libraries(${PROJECT_NAME} rats_tls)
+
+install(TARGETS ${PROJECT_NAME}
+	    DESTINATION ${RATS_TLS_INSTALL_BIN_PATH})
diff --git a/samples/virtcca-server/rats-server.c b/samples/virtcca-server/rats-server.c
new file mode 100644
index 0000000..e48723c
--- /dev/null
+++ b/samples/virtcca-server/rats-server.c
@@ -0,0 +1,350 @@
+/* Copyright (c) 2021 Intel Corporation
+ * Copyright (c) 2020-2021 Alibaba Cloud
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <getopt.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <rats-tls/api.h>
+#include <rats-tls/log.h>
+#include <rats-tls/claim.h>
+
+#define DEFAULT_PORT 1234
+#define DEFAULT_IP   "0.0.0.0" /* Listern to connections from any ip */
+#define TOKEN "ATTESTATION_PASS"
+#define IMA_MEASUREMENTS_PATH "/sys/kernel/security/ima/binary_runtime_measurements"
+#define IMA_READ_BLCOK_SIZE 1024
+
+rats_tls_err_t read_ima_measurements(uint8_t **value, size_t *size)
+{
+	FILE *file;
+	uint8_t buffer[IMA_READ_BLCOK_SIZE];
+	size_t byte_read;
+
+	file = fopen(IMA_MEASUREMENTS_PATH, "rb");
+	if (file == NULL) {
+		RTLS_ERR("Error opening file: %s\n", strerror(errno));
+		return RATS_TLS_ERR_INVALID;
+	}
+	RTLS_INFO("file opened: %s\n", IMA_MEASUREMENTS_PATH);
+
+	while ((byte_read = fread(buffer, 1, IMA_READ_BLCOK_SIZE, file)) > 0) {
+		uint8_t *content = realloc(*value, *size + byte_read);
+		if (content == NULL) {
+			free(*value);
+			RTLS_ERR("memory reallocation failed");
+			return RATS_TLS_ERR_NO_MEM;
+		}
+
+		*value = content;
+		memcpy(*value + *size, buffer, byte_read);
+		*size += byte_read;
+	}
+
+	fclose(file);
+	return RATS_TLS_ERR_NONE;
+}
+
+int rats_tls_server_startup(rats_tls_log_level_t log_level, char *attester_type,
+			    char *verifier_type, char *tls_type, char *crypto_type, bool mutual,
+				bool ima, bool provide_endorsements, char *ip, int port)
+{
+	rats_tls_conf_t conf;
+	rats_tls_err_t ret;
+	uint8_t *ima_meas = NULL;
+	size_t ima_size = 0;
+    char pass_token[] = TOKEN;
+    int pass_token_len = sizeof(pass_token);
+	memset(&conf, 0, sizeof(conf));
+	conf.log_level = log_level;
+	strcpy(conf.attester_type, attester_type);
+	strcpy(conf.verifier_type, verifier_type);
+	strcpy(conf.tls_type, tls_type);
+	strcpy(conf.crypto_type, crypto_type);
+
+	conf.cert_algo = RATS_TLS_CERT_ALGO_DEFAULT;
+	conf.flags |= RATS_TLS_CONF_FLAGS_SERVER;
+	if (mutual)
+		conf.flags |= RATS_TLS_CONF_FLAGS_MUTUAL;
+	if (ima)
+		ret = read_ima_measurements(&ima_meas, &ima_size);
+		if (ret == 0 && ima_size != 0) {
+			RTLS_INFO("read %zu bytes from binary_runtime_measurements\n", ima_size);
+			claim_t custom_claims[1] = {
+				{ .name = "ima", .value = ima_meas, .value_size = ima_size }
+			};
+			conf.custom_claims = (claim_t *)custom_claims;
+			conf.custom_claims_length = 1;
+			RTLS_INFO("Step\n");
+		} else {
+			RTLS_ERR("failed to read binary_runtime_measurements\n");
+		}
+	if (provide_endorsements)
+		conf.flags |= RATS_TLS_CONF_FLAGS_PROVIDE_ENDORSEMENTS;
+
+	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+	if (sockfd < 0) {
+		RTLS_ERR("Failed to call socket()");
+		return -1;
+	}
+
+	int reuse = 1;
+	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&reuse, sizeof(int)) < 0) {
+		RTLS_ERR("Failed to call setsockopt()");
+		return -1;
+	}
+
+	/* Set keepalive options */
+	int flag = 1;
+	int tcp_keepalive_time = 30;
+	int tcp_keepalive_intvl = 10;
+	int tcp_keepalive_probes = 5;
+	if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag)) < 0) {
+		RTLS_ERR("Failed to call setsockopt()");
+		return -1;
+	}
+	if (setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepalive_time,
+		       sizeof(tcp_keepalive_time)) < 0) {
+		RTLS_ERR("Failed to call setsockopt()");
+		return -1;
+	}
+	if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepalive_intvl,
+		       sizeof(tcp_keepalive_intvl)) < 0) {
+		RTLS_ERR("Failed to call setsockopt()");
+		return -1;
+	}
+	if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &tcp_keepalive_probes,
+		       sizeof(tcp_keepalive_probes)) < 0) {
+		RTLS_ERR("Failed to call setsockopt()");
+		return -1;
+	}
+
+	struct sockaddr_in s_addr;
+	memset(&s_addr, 0, sizeof(s_addr));
+	s_addr.sin_family = AF_INET;
+	s_addr.sin_addr.s_addr = inet_addr(ip);
+	s_addr.sin_port = htons(port);
+
+	/* Bind the server socket */
+	if (bind(sockfd, (struct sockaddr *)&s_addr, sizeof(s_addr)) == -1) {
+		RTLS_ERR("Failed to call bind()");
+		return -1;
+	}
+
+	/* Listen for a new connection, allow 5 pending connections */
+	if (listen(sockfd, 5) == -1) {
+		RTLS_ERR("Failed to call listen()");
+		return -1;
+	}
+
+	rats_tls_handle handle;
+
+	ret = rats_tls_init(&conf, &handle);
+	if (ret != RATS_TLS_ERR_NONE) {
+		RTLS_ERR("Failed to initialize rats tls %#x\n", ret);
+		goto err;
+	}
+
+	ret = rats_tls_set_verification_callback(&handle, NULL);
+	if (ret != RATS_TLS_ERR_NONE) {
+		RTLS_ERR("Failed to set verification callback %#x\n", ret);
+		goto err;
+	}
+
+	while (1) {
+		RTLS_INFO("Waiting for a connection ...\n");
+
+		/* Accept client connections */
+		struct sockaddr_in c_addr;
+		socklen_t size = sizeof(c_addr);
+
+		int connd = accept(sockfd, (struct sockaddr *)&c_addr, &size);
+		if (connd < 0) {
+			RTLS_ERR("Failed to call accept()");
+			continue;
+		}
+
+		ret = rats_tls_negotiate(handle, connd);
+		if (ret != RATS_TLS_ERR_NONE) {
+			RTLS_ERR("Failed to negotiate %#x\n", ret);
+			continue;
+		}
+
+		RTLS_DEBUG("Client connected successfully\n");
+
+		char buf[1024];
+		size_t len = sizeof(buf);
+		ret = rats_tls_receive(handle, buf, &len);
+		if (ret != RATS_TLS_ERR_NONE) {
+			RTLS_ERR("Failed to receive %#x\n", ret);
+			continue;
+		}
+
+		if (len >= sizeof(buf))
+			len = sizeof(buf) - 1;
+		buf[len] = '\0';
+
+		RTLS_INFO("Received from Client: %s\n", buf);
+
+        if (strncmp(buf, pass_token, pass_token_len) == 0) {
+            strcpy(buf, "Attestation Passed, Swtiching Root.....");
+            /* Reply back to the client */
+			len = sizeof(buf);
+            ret = rats_tls_transmit(handle, buf, &len);
+            if (ret != RATS_TLS_ERR_NONE) {
+                RTLS_ERR("Failed to transmit %#x\n", ret);
+            }
+            break;
+        } else {
+            strcpy(buf, "Attestation Failed, Continue.....");
+            /* Reply back to the client */
+			len = sizeof(buf);
+            ret = rats_tls_transmit(handle, buf, &len);
+            if (ret != RATS_TLS_ERR_NONE) {
+                RTLS_ERR("Failed to transmit %#x\n", ret);
+            }
+			continue;
+        }
+
+		close(connd);
+	}
+
+	if (ima_meas != NULL) {
+		free(ima_meas);
+	}
+
+	shutdown(sockfd, SHUT_RDWR);
+	close(sockfd);
+	ret = rats_tls_cleanup(handle);
+	if (ret != RATS_TLS_ERR_NONE) {
+		RTLS_ERR("Failed to cleanup %#x\n", ret);
+		return ret;
+	} else {
+		return 0x67;
+	}
+
+err:
+	/* Ignore the error code of cleanup in order to return the prepositional error */
+	shutdown(sockfd, SHUT_RDWR);
+    close(sockfd);
+	rats_tls_cleanup(handle);
+	return -1;
+
+}
+
+int main(int argc, char **argv)
+{
+	char *const short_options = "a:v:t:c:mIel:i:p:h";
+	// clang-format off
+        struct option long_options[] = {
+                { "attester", required_argument, NULL, 'a' },
+                { "verifier", required_argument, NULL, 'v' },
+                { "tls", required_argument, NULL, 't' },
+                { "crypto", required_argument, NULL, 'c' },
+                { "mutual", no_argument, NULL, 'm' },
+				{ "ima", no_argument, NULL, 'I'},
+                { "endorsements", no_argument, NULL, 'e' },
+                { "log-level", required_argument, NULL, 'l' },
+                { "ip", required_argument, NULL, 'i' },
+                { "port", required_argument, NULL, 'p' },
+                { "help", no_argument, NULL, 'h' },
+                { 0, 0, 0, 0 }
+        };
+	// clang-format on
+
+	char *attester_type = "";
+	char *verifier_type = "";
+	char *tls_type = "";
+	char *crypto_type = "";
+	bool mutual = false;
+	bool ima = false;
+	bool provide_endorsements = false;
+	rats_tls_log_level_t log_level = RATS_TLS_LOG_LEVEL_INFO;
+	char *ip = DEFAULT_IP;
+	int port = DEFAULT_PORT;
+	int opt;
+
+	do {
+		opt = getopt_long(argc, argv, short_options, long_options, NULL);
+		switch (opt) {
+		case 'a':
+			attester_type = optarg;
+			break;
+		case 'v':
+			verifier_type = optarg;
+			break;
+		case 't':
+			tls_type = optarg;
+			break;
+		case 'c':
+			crypto_type = optarg;
+			break;
+		case 'm':
+			mutual = true;
+			break;
+		case 'I':
+			ima = true;
+			break;
+		case 'e':
+			provide_endorsements = true;
+			break;
+		case 'l':
+			if (!strcasecmp(optarg, "debug"))
+				log_level = RATS_TLS_LOG_LEVEL_DEBUG;
+			else if (!strcasecmp(optarg, "info"))
+				log_level = RATS_TLS_LOG_LEVEL_INFO;
+			else if (!strcasecmp(optarg, "warn"))
+				log_level = RATS_TLS_LOG_LEVEL_WARN;
+			else if (!strcasecmp(optarg, "error"))
+				log_level = RATS_TLS_LOG_LEVEL_ERROR;
+			else if (!strcasecmp(optarg, "fatal"))
+				log_level = RATS_TLS_LOG_LEVEL_FATAL;
+			else if (!strcasecmp(optarg, "off"))
+				log_level = RATS_TLS_LOG_LEVEL_NONE;
+			break;
+		case 'i':
+			ip = optarg;
+			break;
+		case 'p':
+			port = atoi(optarg);
+			break;
+		case -1:
+			break;
+		case 'h':
+			puts("    Usage:\n\n"
+			     "        rats-tls-server <options> [arguments]\n\n"
+			     "    Options:\n\n"
+			     "        --attester/-a value   set the type of quote attester\n"
+			     "        --verifier/-v value   set the type of quote verifier\n"
+			     "        --tls/-t value        set the type of tls wrapper\n"
+			     "        --crypto/-c value     set the type of crypto wrapper\n"
+			     "        --mutual/-m           set to enable mutual attestation\n"
+				 "        --ima/-I              set to enable ima\n"
+			     "        --endorsements/-e     set to let attester provide endorsements\n"
+			     "        --log-level/-l        set the log level\n"
+			     "        --ip/-i               set the listening ip address\n"
+			     "        --port/-p             set the listening tcp port\n"
+			     "        --help/-h             show the usage\n");
+			exit(1);
+			/* Avoid compiling warning */
+			break;
+		default:
+			exit(1);
+		}
+	} while (opt != -1);
+
+	global_log_level = log_level;
+
+	return rats_tls_server_startup(log_level, attester_type, verifier_type, tls_type,
+				       crypto_type, mutual, ima, provide_endorsements, ip, port);
+}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index de69760..98e75b7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,9 +2,12 @@
 set(INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
                  ${CMAKE_CURRENT_SOURCE_DIR}/include/rats-tls
                  ${CMAKE_CURRENT_SOURCE_DIR}/include/internal
-                 /opt/intel/sgxsdk/include
-                 /usr/include
+                 /usr/include/
                  )
+if(NOT VIRTCCA)
+    list(APPEND INCLUDE_DIRS /opt/intel/sgxsdk/include)
+endif()
+
 if(SGX)
     list(APPEND INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include/edl
                              ${CMAKE_BINARY_DIR}/src/sgx/trust
@@ -121,4 +124,4 @@ set(RTLS_INCLUDE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/rats-tls/api.h
                        )
 install(DIRECTORY DESTINATION ${RATS_TLS_INSTALL_INCLUDE_PATH})
 install(FILES ${RTLS_INCLUDE_FILES}
-DESTINATION ${RATS_TLS_INSTALL_INCLUDE_PATH})
+        DESTINATION ${RATS_TLS_INSTALL_INCLUDE_PATH})
diff --git a/src/api/rats_tls_init.c b/src/api/rats_tls_init.c
index 39e64cd..6ddacf6 100644
--- a/src/api/rats_tls_init.c
+++ b/src/api/rats_tls_init.c
@@ -121,14 +121,6 @@ rats_tls_err_t rats_tls_init(const rats_tls_conf_t *conf, rats_tls_handle *handl
 	if (err != RATS_TLS_ERR_NONE)
 		goto err_ctx;
 
-	/* Check whether requiring to generate TLS certificate */
-	if ((ctx->config.flags & RATS_TLS_CONF_FLAGS_SERVER) ||
-	    (ctx->config.flags & RATS_TLS_CONF_FLAGS_MUTUAL)) {
-		err = rtls_core_generate_certificate(ctx);
-		if (err != RATS_TLS_ERR_NONE)
-			goto err_ctx;
-	}
-
 	*handle = ctx;
 
 	RTLS_DEBUG("the handle %p returned\n", ctx);
diff --git a/src/attesters/CMakeLists.txt b/src/attesters/CMakeLists.txt
index 103c8d0..7bb2ca6 100644
--- a/src/attesters/CMakeLists.txt
+++ b/src/attesters/CMakeLists.txt
@@ -19,3 +19,7 @@ endif()
 if(SGX)
     add_subdirectory(sgx-la)
 endif()
+
+if(VIRTCCA)
+    add_subdirectory(virtcca)
+endif()
\ No newline at end of file
diff --git a/src/attesters/api/enclave_attester_register.c b/src/attesters/api/enclave_attester_register.c
index a59849c..a5a8fd1 100644
--- a/src/attesters/api/enclave_attester_register.c
+++ b/src/attesters/api/enclave_attester_register.c
@@ -12,7 +12,7 @@
 #include "internal/cpu.h"
 
 enclave_attester_err_t enclave_attester_register(const enclave_attester_opts_t *opts)
-{
+{	
 	if (!opts)
 		return -ENCLAVE_ATTESTER_ERR_INVALID;
 
@@ -26,9 +26,7 @@ enclave_attester_err_t enclave_attester_register(const enclave_attester_opts_t *
 			// clang-format on
 			return -ENCLAVE_ATTESTER_ERR_CPU_UNSUPPORTED;
 		}
-	}
-
-	if (opts->flags & ENCLAVE_ATTESTER_OPTS_FLAGS_SNP_GUEST) {
+	} else if (opts->flags & ENCLAVE_ATTESTER_OPTS_FLAGS_SNP_GUEST) {
 		if (!is_snpguest_supported()) {
 			// clang-format off
 			RTLS_DEBUG("failed to register the attester '%s' due to lack of SNP Guest capability\n",
@@ -36,9 +34,7 @@ enclave_attester_err_t enclave_attester_register(const enclave_attester_opts_t *
 			// clang-format on
 			return -ENCLAVE_ATTESTER_ERR_CPU_UNSUPPORTED;
 		}
-	}
-
-	if (opts->flags & ENCLAVE_ATTESTER_OPTS_FLAGS_SEV_GUEST) {
+	} else if (opts->flags & ENCLAVE_ATTESTER_OPTS_FLAGS_SEV_GUEST) {
 		if (!is_sevguest_supported()) {
 			// clang-format off
 			RTLS_DEBUG("failed to register the attester '%s' due to lack of SEV(-ES) Guest capability\n",
@@ -46,9 +42,7 @@ enclave_attester_err_t enclave_attester_register(const enclave_attester_opts_t *
 			// clang-format on
 			return -ENCLAVE_ATTESTER_ERR_CPU_UNSUPPORTED;
 		}
-	}
-
-	if (opts->flags & ENCLAVE_ATTESTER_OPTS_FLAGS_CSV_GUEST) {
+	} else if (opts->flags & ENCLAVE_ATTESTER_OPTS_FLAGS_CSV_GUEST) {
 		if (!is_csvguest_supported()) {
 			// clang-format off
 			RTLS_DEBUG("failed to register the attester '%s' due to lack of CSV Guest capability\n",
@@ -56,6 +50,21 @@ enclave_attester_err_t enclave_attester_register(const enclave_attester_opts_t *
 			// clang-format on
 			return -ENCLAVE_ATTESTER_ERR_CPU_UNSUPPORTED;
 		}
+	} else if (opts->flags & ENCLAVE_ATTESTER_OPTS_FLAGS_VIRTCCA_GUEST) {
+		if (!is_virtccaguest_supported()) {
+			// clang-format off
+			RTLS_DEBUG("failed to register the attester '%s' due to lack of VirtCCA Guest capability\n",
+				   opts->type);
+			// clang-format on
+			return -ENCLAVE_ATTESTER_ERR_CPU_UNSUPPORTED;
+		}
+	} else if (opts->flags & ENCLAVE_ATTESTER_OPTS_FLAGS_VIRTCCA_FAKE) {
+		RTLS_DEBUG("ignore checking capability for attester '%s'\n", opts->type);
+	} else if (opts->flags == ENCLAVE_ATTESTER_FLAGS_DEFAULT) {
+		RTLS_DEBUG("ignore checking capability for nullattester\n");	
+	} else {
+		RTLS_DEBUG("unknown attester opts->flag '%lx'\n", opts->flags);
+		return -ENCLAVE_ATTESTER_ERR_UNKNOWN;
 	}
 
 	enclave_attester_opts_t *new_opts = (enclave_attester_opts_t *)malloc(sizeof(*new_opts));
diff --git a/src/attesters/csv/collect_evidence.c b/src/attesters/csv/collect_evidence.c
index 6707cf9..d7079c8 100644
--- a/src/attesters/csv/collect_evidence.c
+++ b/src/attesters/csv/collect_evidence.c
@@ -239,8 +239,7 @@ static int collect_attestation_evidence(uint8_t *hash, uint32_t hash_len,
 	// clang-fomat off
 	/* Prepare user defined data (challenge and mnonce) */
 	memcpy(user_data->data, hash,
-	       hash_len <= CSV_ATTESTATION_USER_DATA_SIZE ? hash_len :
-							    CSV_ATTESTATION_USER_DATA_SIZE);
+	       hash_len <= CSV_ATTESTATION_USER_DATA_SIZE ? hash_len : CSV_ATTESTATION_USER_DATA_SIZE);
 	// clang-format on
 
 	gen_random_bytes(user_data->mnonce, CSV_ATTESTATION_MNONCE_SIZE);
diff --git a/src/attesters/csv/pre_init.c b/src/attesters/csv/pre_init.c
index 4a4e1ea..9447192 100644
--- a/src/attesters/csv/pre_init.c
+++ b/src/attesters/csv/pre_init.c
@@ -11,10 +11,13 @@ enclave_attester_err_t csv_attester_pre_init(void)
 {
 	RTLS_DEBUG("called\n");
 
-	if (!system("wget -V >/dev/null 2>&1"))
-		return ENCLAVE_ATTESTER_ERR_NONE;
+	enclave_attester_err_t err = ENCLAVE_ATTESTER_ERR_NONE;
 
-	RTLS_ERR("Please install wget for csv attester\n");
+	char *cmdline_str = "which wget 1> /dev/null 2> /dev/null";
+	if (system(cmdline_str) != 0) {
+		RTLS_ERR("please install wget for csv attest\n");
+		err = -ENCLAVE_ATTESTER_ERR_NO_TOOL;
+	}
 
-	return -ENCLAVE_ATTESTER_ERR_NO_TOOL;
+	return err;
 }
diff --git a/src/attesters/internal/rtls_enclave_attester_load_all.c b/src/attesters/internal/rtls_enclave_attester_load_all.c
index 6e997ee..7aaa04e 100644
--- a/src/attesters/internal/rtls_enclave_attester_load_all.c
+++ b/src/attesters/internal/rtls_enclave_attester_load_all.c
@@ -41,23 +41,20 @@ rats_tls_err_t rtls_enclave_attester_load_all(void)
 	unsigned int total_loaded = 0;
 	rtls_dirent *ptr;
 	while ((rtls_readdir(dir, &ptr)) != 1) {
-		const char *d_name = ptr->d_name;
-
-		if (!strcmp(d_name, ".") || !strcmp(d_name, ".."))
+		if (!strcmp(ptr->d_name, ".") || !strcmp(ptr->d_name, ".."))
 			continue;
-
-		if (strncmp(d_name + strlen(d_name) - strlen(PATTERN_SUFFIX), PATTERN_SUFFIX,
-			    strlen(PATTERN_SUFFIX)))
+		if (strncmp(ptr->d_name + strlen(ptr->d_name) - strlen(PATTERN_SUFFIX),
+			    PATTERN_SUFFIX, strlen(PATTERN_SUFFIX)))
 			continue;
 
 #ifdef OCCLUM
 		/* Occlum can't identify the d_type of the file, always return DT_UNKNOWN */
-		if (strncmp(d_name + strlen(d_name) - strlen(PATTERN_SUFFIX), PATTERN_SUFFIX,
-			    strlen(PATTERN_SUFFIX)) == 0) {
+		if (strncmp(ptr->d_name + strlen(ptr->d_name) - strlen(PATTERN_SUFFIX),
+			    PATTERN_SUFFIX, strlen(PATTERN_SUFFIX)) == 0) {
 #else
 		if (ptr->d_type == DT_REG || ptr->d_type == DT_LNK) {
 #endif
-			if (rtls_enclave_attester_load_single(d_name) == RATS_TLS_ERR_NONE)
+			if (rtls_enclave_attester_load_single(ptr->d_name) == RATS_TLS_ERR_NONE)
 				++total_loaded;
 		}
 	}
diff --git a/src/attesters/tdx-ecdsa/pre_init.c b/src/attesters/tdx-ecdsa/pre_init.c
index c59114a..bd5d93d 100644
--- a/src/attesters/tdx-ecdsa/pre_init.c
+++ b/src/attesters/tdx-ecdsa/pre_init.c
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+#include <internal/cpu.h>
 #include <rats-tls/attester.h>
 #include <rats-tls/log.h>
 
diff --git a/src/attesters/virtcca/CMakeLists.txt b/src/attesters/virtcca/CMakeLists.txt
new file mode 100644
index 0000000..4fc4818
--- /dev/null
+++ b/src/attesters/virtcca/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Project name
+project(attester_virtcca)
+
+# Set include directory
+list(APPEND INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
+
+include_directories(${INCLUDE_DIRS})
+
+# Set dependency library directory
+set(LIBRARY_DIRS ${CMAKE_BINARY_DIR}/src
+                 ${RATS_TLS_INSTALL_LIB_PATH}
+                 )
+link_directories(${LIBRARY_DIRS})
+
+# Set source file
+set(SOURCES cleanup.c
+            collect_evidence.c
+            init.c
+            main.c
+            pre_init.c
+            )
+
+# Generate library
+add_library(${PROJECT_NAME} SHARED ${SOURCES})
+target_link_libraries(${PROJECT_NAME} ${RATS_TLS_LDFLAGS} ${RTLS_LIB} vccaattestation)
+set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${VERSION} SOVERSION ${VERSION_MAJOR})
+
+# Install library
+install(TARGETS ${PROJECT_NAME}
+        DESTINATION ${RATS_TLS_INSTALL_LIBA_PATH})
diff --git a/src/attesters/virtcca/cleanup.c b/src/attesters/virtcca/cleanup.c
new file mode 100644
index 0000000..fe3ec58
--- /dev/null
+++ b/src/attesters/virtcca/cleanup.c
@@ -0,0 +1,14 @@
+#include <rats-tls/log.h>
+#include <rats-tls/attester.h>
+#include <attestation.h>
+
+enclave_attester_err_t virtcca_attester_cleanup(__attribute__((unused)) enclave_attester_ctx_t *ctx)
+{
+	RTLS_DEBUG("called\n");
+	
+	tsi_ctx *virtcca_ctx = (tsi_ctx *)ctx->attester_private;
+
+	tsi_free_ctx(virtcca_ctx);
+
+	return ENCLAVE_ATTESTER_ERR_NONE;
+}
diff --git a/src/attesters/virtcca/collect_evidence.c b/src/attesters/virtcca/collect_evidence.c
new file mode 100644
index 0000000..2f15551
--- /dev/null
+++ b/src/attesters/virtcca/collect_evidence.c
@@ -0,0 +1,67 @@
+#include <rats-tls/log.h>
+#include <rats-tls/attester.h>
+#include <string.h>
+#include <attestation.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define CHALLENGE_SIZE 64
+
+enclave_attester_err_t virtcca_collect_evidence(enclave_attester_ctx_t *ctx,
+						     attestation_evidence_t *evidence,
+						     rats_tls_cert_algo_t algo, uint8_t *hash,
+						     uint32_t hash_len)
+{
+	RTLS_DEBUG("ctx %p, evidence %p, algo %d, hash %p\n", ctx, evidence, algo, hash);
+	tsi_ctx *virtcca_ctx = tsi_new_ctx();
+	if (!virtcca_ctx) {
+        RTLS_ERR("failed to open device: /dev/tsi");
+		return -ENCLAVE_ATTESTER_ERR_NO_TOOL;
+    }
+	unsigned char challenge[CHALLENGE_SIZE] = {0};
+	size_t challenge_len = CHALLENGE_SIZE;
+	size_t token_len;
+	size_t device_cert_len;
+	unsigned char *token;
+	unsigned char *device_cert;
+	virtcca_attestation_evidence_t *virtcca_token = &evidence->virtcca;
+    int ret;
+
+	/* Prepare user defined data, i.e., challenge */
+	if (hash_len > CHALLENGE_SIZE) {
+		RTLS_ERR("hash length: %d, challenge_size: %d\n", hash_len, CHALLENGE_SIZE);
+	}
+	challenge_len = hash_len <= CHALLENGE_SIZE ? hash_len : CHALLENGE_SIZE;
+	memcpy(challenge, hash, challenge_len);
+
+	token = virtcca_token->report + sizeof(token_len);
+	token_len = REPORT_MAX_LENGTH - sizeof(token_len);
+	ret = get_attestation_token(virtcca_ctx, challenge, challenge_len, token, &token_len);
+	if (ret != 0) {
+		RTLS_ERR("failed to get attestation token (%d)\n", ret);
+		tsi_free_ctx(virtcca_ctx);
+		return -ENCLAVE_ATTESTER_ERR_INVALID;
+	}
+	memcpy(virtcca_token->report, &token_len, sizeof(token_len));
+
+	device_cert = virtcca_token->report + sizeof(token_len) + token_len + sizeof(device_cert_len);
+	device_cert_len = REPORT_MAX_LENGTH - sizeof(token_len) - token_len - sizeof(device_cert_len);
+	ret = get_dev_cert(virtcca_ctx, device_cert, &device_cert_len);
+	if (ret != 0) {
+		RTLS_ERR("failed to get device cert (%d)\n", ret);
+		tsi_free_ctx(virtcca_ctx);
+		return -ENCLAVE_ATTESTER_ERR_INVALID;
+	}
+	memcpy(virtcca_token->report + sizeof(token_len) + token_len, &device_cert_len, sizeof(device_cert_len));
+
+	virtcca_token->report_len = token_len + device_cert_len + sizeof(token_len) + sizeof(device_cert_len);
+
+	tsi_free_ctx(virtcca_ctx);
+
+	snprintf(evidence->type, sizeof(evidence->type), "virtcca");
+
+	RTLS_DEBUG("ctx %p, evidence %p, report_len %d\n", ctx, evidence, evidence->sev.report_len);
+
+	return ENCLAVE_ATTESTER_ERR_NONE;
+}
diff --git a/src/attesters/virtcca/init.c b/src/attesters/virtcca/init.c
new file mode 100644
index 0000000..0b72628
--- /dev/null
+++ b/src/attesters/virtcca/init.c
@@ -0,0 +1,29 @@
+#include <rats-tls/log.h>
+#include <rats-tls/attester.h>
+#include <attestation.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+enclave_attester_err_t virtcca_attester_init(enclave_attester_ctx_t *ctx, rats_tls_cert_algo_t algo)
+{
+	RTLS_DEBUG("ctx %p, algo %d\n", ctx, algo);
+	int ret;
+	int major, minor;
+	tsi_ctx *virtcca_ctx = tsi_new_ctx();
+	if (!virtcca_ctx) {
+        RTLS_ERR("failed to open device: /dev/tsi");
+		return -ENCLAVE_ATTESTER_ERR_NO_TOOL;
+    }
+
+	ret = get_version(virtcca_ctx, &major, &minor);
+    if (ret != 0) {
+        RTLS_ERR("failed to get TSI version (%d)", ret);
+        return -ENCLAVE_ATTESTER_ERR_INVALID;
+    }
+
+    RTLS_DEBUG("TSI version %d.%d advertised\n", major, minor);
+
+	ctx->attester_private = virtcca_ctx;
+
+	return ENCLAVE_ATTESTER_ERR_NONE;
+}
diff --git a/src/attesters/virtcca/main.c b/src/attesters/virtcca/main.c
new file mode 100644
index 0000000..89426a0
--- /dev/null
+++ b/src/attesters/virtcca/main.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <rats-tls/attester.h>
+#include <rats-tls/log.h>
+
+extern enclave_attester_err_t enclave_attester_register(enclave_attester_opts_t *);
+extern enclave_attester_err_t virtcca_attester_pre_init(void);
+extern enclave_attester_err_t virtcca_attester_init(enclave_attester_ctx_t *,
+												 	rats_tls_cert_algo_t algo);
+extern enclave_attester_err_t virtcca_collect_evidence(enclave_attester_ctx_t *,
+													   attestation_evidence_t *,
+													   rats_tls_cert_algo_t algo, uint8_t *,
+													   uint32_t hash_len);
+extern enclave_attester_err_t virtcca_attester_cleanup(enclave_attester_ctx_t *);
+
+static enclave_attester_opts_t virtcca_attester_opts = {
+	.api_version = ENCLAVE_ATTESTER_API_VERSION_DEFAULT,
+	.flags = ENCLAVE_ATTESTER_OPTS_FLAGS_VIRTCCA_GUEST,
+	.name = "virtcca",
+	.priority = 15,
+	.pre_init = virtcca_attester_pre_init,
+	.init = virtcca_attester_init,
+	.collect_evidence = virtcca_collect_evidence,
+	.cleanup = virtcca_attester_cleanup,
+};
+
+void __attribute__((constructor)) libattester_virtcca_init(void)
+{
+	RTLS_DEBUG("called\n");
+
+	enclave_attester_err_t err = enclave_attester_register(&virtcca_attester_opts);
+	if (err != ENCLAVE_ATTESTER_ERR_NONE)
+		RTLS_DEBUG("failed to register the enclave attester 'virtcca' %#x\n", err);
+}
diff --git a/src/attesters/virtcca/pre_init.c b/src/attesters/virtcca/pre_init.c
new file mode 100644
index 0000000..0fd3c55
--- /dev/null
+++ b/src/attesters/virtcca/pre_init.c
@@ -0,0 +1,9 @@
+#include <rats-tls/log.h>
+#include <rats-tls/attester.h>
+
+enclave_attester_err_t virtcca_attester_pre_init(void)
+{
+	RTLS_DEBUG("called\n");
+
+	return ENCLAVE_ATTESTER_ERR_NONE;
+}
diff --git a/src/core/cpu.c b/src/core/cpu.c
index ad48924..f1d53cf 100644
--- a/src/core/cpu.c
+++ b/src/core/cpu.c
@@ -20,7 +20,7 @@
 #include "rtls_t.h"
 #endif
 // clang-format on
-
+#ifndef __aarch64__ /* AARCH64 */
 #ifndef SGX
 // clang-format off
 static inline void cpuid(int *eax, int *ebx, int *ecx, int *edx)
@@ -51,10 +51,12 @@ static bool is_sgx_device(const char *dev)
 {
 	struct stat st;
 
-	if (stat(dev, &st))
-		return false;
+	if (!stat(dev, &st)) {
+		if ((st.st_mode & S_IFCHR) && (major(st.st_rdev) == SGX_DEVICE_MAJOR_NUM))
+			return true;
+	}
 
-	return (st.st_mode & S_IFCHR) && (major(st.st_rdev) == SGX_DEVICE_MAJOR_NUM);
+	return false;
 }
 
 static bool is_legacy_oot_kernel_driver(void)
@@ -194,7 +196,6 @@ bool is_tdguest_supported(void)
 static uint64_t read_msr(uint32_t reg)
 {
 	int fd = open("/dev/cpu/0/msr", O_RDONLY);
-
 	if (fd < 0) {
 		RTLS_ERR("failed to open msr\n");
 		return 0;
@@ -203,7 +204,7 @@ static uint64_t read_msr(uint32_t reg)
 	uint64_t data;
 	if (pread(fd, &data, sizeof(data), reg) != sizeof(data)) {
 		close(fd);
-		RTLS_ERR("failed to read msr %#x\n", reg);
+		RTLS_DEBUG("failed to read msr %#x\n", reg);
 		return 0;
 	}
 
@@ -213,39 +214,26 @@ static uint64_t read_msr(uint32_t reg)
 }
 #endif
 
-static bool is_amd_cpu(void)
-{
-	int cpu_info[4] = { 0, 0, 0, 0 };
-
-	__cpuidex(cpu_info, 0, 0);
-
-	/* The twelve 8-bit ASCII character codes that form the
-	 * string "AuthenticAMD".
-	 */
-	return (cpu_info[1] == 0x68747541 && cpu_info[2] == 0x444d4163 &&
-		cpu_info[3] == 0x69746e65);
-}
+#define X86_CPUID_VENDOR_HygonGenuine_ebx 0x6f677948
+#define X86_CPUID_VENDOR_HygonGenuine_ecx 0x656e6975
+#define X86_CPUID_VENDOR_HygonGenuine_edx 0x6e65476e
 
-static bool is_hygon_cpu(void)
+/* check CPU vendor of the guest */
+bool is_hygon_cpu(void)
 {
 	int cpu_info[4] = { 0, 0, 0, 0 };
 
 	__cpuidex(cpu_info, 0, 0);
 
-	/* The twelve 8-bit ASCII character codes that form the
-         * string "HygonGenuine".
-         */
-	return (cpu_info[1] == 0x6f677948 && cpu_info[2] == 0x656e6975 &&
-		cpu_info[3] == 0x6e65476e);
+	return (cpu_info[1] == X86_CPUID_VENDOR_HygonGenuine_ebx &&
+		cpu_info[2] == X86_CPUID_VENDOR_HygonGenuine_ecx &&
+		cpu_info[3] == X86_CPUID_VENDOR_HygonGenuine_edx);
 }
 
 /* check whether running in AMD SEV-SNP guest */
 bool is_snpguest_supported(void)
 {
 #ifndef SGX
-	if (!is_amd_cpu())
-		return false;
-
 	return !!(read_msr(SEV_STATUS_MSR) & (1 << SEV_SNP_FLAG));
 #else
 	return false;
@@ -256,11 +244,13 @@ bool is_snpguest_supported(void)
 bool is_sevguest_supported(void)
 {
 #ifndef SGX
-	if (!is_amd_cpu())
-		return false;
+	if (!is_hygon_cpu()) {
+		uint64_t data = read_msr(SEV_STATUS_MSR);
 
-	uint64_t data = read_msr(SEV_STATUS_MSR);
-	return !!data || !!(data & (1 << SEV_ES_FLAG));
+		return !!data || !!(data & (1 << SEV_ES_FLAG));
+	} else {
+		return false;
+	}
 #else
 	return false;
 #endif
@@ -270,12 +260,75 @@ bool is_sevguest_supported(void)
 bool is_csvguest_supported(void)
 {
 #ifndef SGX
-	if (!is_hygon_cpu())
-		return false;
+	if (is_hygon_cpu()) {
+		uint64_t data = read_msr(SEV_STATUS_MSR);
 
-	uint64_t data = read_msr(SEV_STATUS_MSR);
-	return !!(data & ((1 << SEV_FLAG) | (1 << SEV_ES_FLAG)));
+		return !!(data & ((1 << SEV_FLAG) | (1 << SEV_ES_FLAG)));
+	} else {
+		return false;
+	}
 #else
 	return false;
 #endif
 }
+
+/* check whether running in ARM VirtCCA guest */
+bool is_virtccaguest_supported(void)
+{	
+	return false;
+}
+
+#else /* AARCH64 */
+
+bool is_csvguest_supported(void)
+{
+	return false;
+}
+
+bool is_sevguest_supported(void)
+{
+	return false;
+}
+
+bool is_snpguest_supported(void)
+{
+	return false;
+}
+
+static bool is_sgx_device(const char *dev)
+{
+	return false;
+}
+
+static bool is_legacy_oot_kernel_driver(void)
+{
+	return false;
+}
+
+static bool is_in_tree_kernel_driver(void)
+{
+	return false;
+}
+
+static bool is_dcap_1_9_oot_kernel_driver(void)
+{
+	return false;
+}
+
+bool is_tdguest_supported(void)
+{
+	return false;
+}
+
+/* check whether running in ARM VirtCCA guest */
+bool is_virtccaguest_supported(void)
+{	
+	struct stat st;
+	if (stat("/dev/tsi", &st) == 0) {
+		if (S_ISCHR(st.st_mode))
+			return true;
+	}
+	return false;
+}
+
+#endif /* AARCH64 */
\ No newline at end of file
diff --git a/src/core/dice.c b/src/core/dice.c
index 59b3158..f0ac171 100644
--- a/src/core/dice.c
+++ b/src/core/dice.c
@@ -7,10 +7,10 @@
 #include <string.h>
 #include <rats-tls/err.h>
 #include <rats-tls/log.h>
+#include <internal/dice.h>
 #include <rats-tls/cert.h>
 #include <rats-tls/endorsement.h>
 #include <cbor.h>
-#include "internal/dice.h"
 
 uint64_t tag_of_evidence_type(const char *type)
 {
@@ -26,8 +26,11 @@ uint64_t tag_of_evidence_type(const char *type)
 		return OCBR_TAG_EVIDENCE_SEV;
 	} else if (!strcmp(type, "csv")) {
 		return OCBR_TAG_EVIDENCE_CSV;
+	} else if (!strcmp(type, "virtcca")) {
+		return OCBR_TAG_EVIDENCE_VIRTCCA;
+	} else if (!strcmp(type, "virtcca_fake")) {
+		return OCBR_TAG_EVIDENCE_VIRTCCA;
 	}
-
 	RTLS_FATAL("Unhandled evidence type '%s'\n", type);
 	return 0;
 }
@@ -60,6 +63,12 @@ const uint8_t *evidence_get_raw_as_ref(const attestation_evidence_t *evidence, s
 	} else if (!strcmp(evidence->type, "csv")) {
 		data = (const uint8_t *)&evidence->csv.report;
 		size = evidence->csv.report_len;
+	} else if (!strcmp(evidence->type, "virtcca")) {
+		data = (const uint8_t *)&evidence->virtcca.report;
+		size = evidence->virtcca.report_len;
+	} else if (!strcmp(evidence->type, "virtcca_fake")) {
+		data = (const uint8_t *)&evidence->virtcca.report;
+		size = evidence->virtcca.report_len;
 	} else {
 		RTLS_FATAL("Unhandled evidence type '%s'\n", evidence->type);
 		*size_out = 0;
@@ -67,7 +76,11 @@ const uint8_t *evidence_get_raw_as_ref(const attestation_evidence_t *evidence, s
 	}
 	*size_out = (size_t)size;
 	if (size >= 16)
+		#if 1
+		RTLS_INFO(
+		#else
 		RTLS_DEBUG(
+		#endif
 			"evidence raw data [%zu] %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x...\n",
 			size, data[0], data[1], data[2], data[3], data[4], data[5], data[6],
 			data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14],
@@ -79,7 +92,11 @@ int evidence_from_raw(const uint8_t *data, size_t size, uint64_t tag,
 		      attestation_evidence_t *evidence)
 {
 	if (size >= 16)
+		#if 1
+		RTLS_INFO(
+		#else
 		RTLS_DEBUG(
+		#endif
 			"evidence raw data [%zu] %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x...\n",
 			size, data[0], data[1], data[2], data[3], data[4], data[5], data[6],
 			data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14],
@@ -147,8 +164,12 @@ int evidence_from_raw(const uint8_t *data, size_t size, uint64_t tag,
 		memcpy(evidence->type, "csv", sizeof("csv"));
 		memcpy((uint8_t *)&evidence->csv.report, data, size);
 		evidence->csv.report_len = size;
+	} else if (tag == OCBR_TAG_EVIDENCE_VIRTCCA) {
+		memcpy(evidence->type, "virtcca", sizeof("virtcca"));
+		memcpy((uint8_t *)&evidence->virtcca.report, data, size);
+		evidence->virtcca.report_len = size;
 	}
-
+	
 	return 0;
 }
 
@@ -201,6 +222,7 @@ err:
 
 enclave_attester_err_t
 dice_generate_claims_buffer(hash_algo_t pubkey_hash_algo, const uint8_t *pubkey_hash,
+				const uint8_t *nonce, size_t nonce_size, 
 			    const claim_t *custom_claims, size_t custom_claims_length,
 			    uint8_t **claims_buffer_out, size_t *claims_buffer_size_out)
 {
@@ -210,9 +232,8 @@ dice_generate_claims_buffer(hash_algo_t pubkey_hash_algo, const uint8_t *pubkey_
 	size_t pubkey_hash_value_buffer_size = 0;
 
 	/* claims-buffer: { "pubkey-hash" : h'<pubkey-hash-value>', "nonce" : h'<nonce-value>'} */
-	/* Note that the nonce is optional, it's for per-session freshness, which we don't support it yet. */
 	ret = ENCLAVE_ATTESTER_ERR_NO_MEM;
-	root = cbor_new_definite_map(1 + custom_claims_length);
+	root = cbor_new_definite_map(2 + custom_claims_length);
 	if (!root)
 		goto err;
 
@@ -233,6 +254,14 @@ dice_generate_claims_buffer(hash_algo_t pubkey_hash_algo, const uint8_t *pubkey_
 	free(pubkey_hash_value_buffer);
 	pubkey_hash_value_buffer = NULL;
 
+	if (!cbor_map_add(root, (struct cbor_pair) {
+					.key = cbor_move(cbor_build_string(CLAIM_NONCE)),
+					.value = cbor_move(cbor_build_bytestring(
+						nonce,
+						nonce_size)) })) {
+		goto err;
+	}
+		
 	/* Add all user-defined claims to map */
 	ret = ENCLAVE_ATTESTER_ERR_NO_MEM;
 	for (size_t i = 0; i < custom_claims_length; i++) {
@@ -710,7 +739,7 @@ err:
 	return ret;
 }
 
-/* Parse the claims buffer and return the custom claims and pubkey hash. Note that
+/* Parse the claims buffer and return the custom claims, pubkey hash, and nonce. Note that
  * the content of the claims buffer is untrusted user input, and its format match
  * the format defined by Interoperable RA-TLS.
  * 
@@ -719,6 +748,8 @@ err:
  * pubkey_hash_algo_out: The `hash_algo_id` of pubkey `hash-entry`
  * pubkey_hash_out: A buffer for writing pubkey hash to, should be large enough
  *     (MAX_HASH_SIZE) to write the hash.
+ * nonce_out: A buffer for write nonce to, should be large enought to write the value.
+ * nonce_size_out: The size of nonce.
  * custom_claims_out: The list of claims stored in the claims buffer, user-defined
  *     custom claims included only. The caller should manage its memory.
  * custom_claims_length_out: The length of claims list.
@@ -726,6 +757,7 @@ err:
 enclave_verifier_err_t
 dice_parse_claims_buffer(const uint8_t *claims_buffer, size_t claims_buffer_size,
 			 hash_algo_t *pubkey_hash_algo_out, uint8_t *pubkey_hash_out,
+			 uint8_t *nonce_out, size_t *nonce_size_out,
 			 claim_t **custom_claims_out, size_t *custom_claims_length_out)
 {
 	enclave_verifier_err_t ret;
@@ -755,6 +787,7 @@ dice_parse_claims_buffer(const uint8_t *claims_buffer, size_t claims_buffer_size
 
 	{
 		bool found_pubkey_hash = false;
+		bool found_nonce = false;
 
 		/* Get claims from claims buffer */
 		claim_t claims[cbor_map_size(root)];
@@ -791,6 +824,19 @@ dice_parse_claims_buffer(const uint8_t *claims_buffer, size_t claims_buffer_size
 				continue;
 			}
 
+			/* Check nonce */
+			if (key_length == sizeof(CLAIM_NONCE) - 1 &&
+			    !strncmp((char *)key_handle, CLAIM_NONCE, key_length)) {
+				found_nonce = true;
+
+				memcpy(nonce_out, value_handle, value_length);
+				*nonce_size_out = value_length;
+
+				/* The "nonce" is a internal claim and should not be returned to the user
+				 * of rats-tls. So we "continue" here. */
+				continue;
+			}
+
 			/* Put user-defined custom claims into the custom_claims list. */
 			claim_t *claim = &claims[count_claims];
 			/* NOTE: The cbor_string_handle(key) returns a non-null terminated string. And the
@@ -824,6 +870,14 @@ dice_parse_claims_buffer(const uint8_t *claims_buffer, size_t claims_buffer_size
 			goto err_claims;
 		}
 
+		if (!found_nonce) {
+			RTLS_ERR(
+				"failed to find claim with name '%s' from claims list with length %zu\n",
+				CLAIM_NONCE, cbor_map_size(root));
+			ret = ENCLAVE_VERIFIER_ERR_INVALID;
+			goto err_claims;
+		}
+
 		custom_claims = malloc(count_claims * sizeof(claim_t));
 		if (!custom_claims) {
 			ret = ENCLAVE_VERIFIER_ERR_NO_MEM;
diff --git a/src/core/main.c b/src/core/main.c
index 88b8af1..24d58c9 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -25,8 +25,6 @@ rtls_core_context_t global_core_context;
 /* The global log level used by log.h */
 rats_tls_log_level_t global_log_level = RATS_TLS_LOG_LEVEL_DEFAULT;
 
-extern rats_tls_log_level_t get_loglevel_env(const char *name);
-
 // clang-format off
 #ifdef SGX
 #define INSTANCE_NUM  (sizeof(enclave_instance_name) / sizeof(enclave_instance_name[0]))
@@ -42,7 +40,7 @@ void __attribute__((constructor)) librats_tls_init(void)
 {
 	RTLS_DEBUG("called\n");
 
-	global_log_level = get_loglevel_env("RATS_TLS_GLOBAL_LOG_LEVEL");
+	global_log_level = rtls_loglevel_getenv("RATS_TLS_GLOBAL_LOG_LEVEL");
 	if (global_log_level == (rats_tls_log_level_t)-1) {
 		RTLS_FATAL("failed to get log level from env\n");
 		rtls_exit();
diff --git a/src/core/rtls_common.c b/src/core/rtls_common.c
index 7c77600..891f0d8 100644
--- a/src/core/rtls_common.c
+++ b/src/core/rtls_common.c
@@ -41,35 +41,41 @@ void rtls_exit(void)
 	ocall_exit();
 }
 
-rats_tls_log_level_t get_loglevel_env(const char *name)
+rats_tls_log_level_t rtls_loglevel_getenv(const char *name)
 {
-	size_t log_level_len = 8;
+	char *log_level_str = NULL;
+	size_t log_level_len = 32;
 
-	char *log_level_str = calloc(1, log_level_len);
+	log_level_str = calloc(1, log_level_len);
 	if (!log_level_str) {
 		RTLS_ERR("failed to calloc log level string\n");
 		return -1;
 	}
 
 	ocall_getenv(name, log_level_str, log_level_len);
+	if (log_level_str) {
+		if (!strcmp(log_level_str, "debug") || !strcmp(log_level_str, "DEBUG")) {
+			free(log_level_str);
+			return RATS_TLS_LOG_LEVEL_DEBUG;
+		} else if (!strcmp(log_level_str, "info") || !strcmp(log_level_str, "INFO")) {
+			free(log_level_str);
+			return RATS_TLS_LOG_LEVEL_INFO;
+		} else if (!strcmp(log_level_str, "warn") || !strcmp(log_level_str, "WARN")) {
+			free(log_level_str);
+			return RATS_TLS_LOG_LEVEL_WARN;
+		} else if (!strcmp(log_level_str, "error") || !strcmp(log_level_str, "ERROR")) {
+			free(log_level_str);
+			return RATS_TLS_LOG_LEVEL_ERROR;
+		} else if (!strcmp(log_level_str, "fatal") || !strcmp(log_level_str, "FATAL")) {
+			free(log_level_str);
+			return RATS_TLS_LOG_LEVEL_FATAL;
+		} else if (!strcmp(log_level_str, "off") || !strcmp(log_level_str, "OFF")) {
+			free(log_level_str);
+			return RATS_TLS_LOG_LEVEL_NONE;
+		}
+	}
 
-	rats_tls_log_level_t level = RATS_TLS_LOG_LEVEL_DEFAULT;
-	if (!strcmp(log_level_str, "debug") || !strcmp(log_level_str, "DEBUG"))
-		level = RATS_TLS_LOG_LEVEL_DEBUG;
-	else if (!strcmp(log_level_str, "info") || !strcmp(log_level_str, "INFO"))
-		level = RATS_TLS_LOG_LEVEL_INFO;
-	else if (!strcmp(log_level_str, "warn") || !strcmp(log_level_str, "WARN"))
-		level = RATS_TLS_LOG_LEVEL_WARN;
-	else if (!strcmp(log_level_str, "error") || !strcmp(log_level_str, "ERROR"))
-		level = RATS_TLS_LOG_LEVEL_ERROR;
-	else if (!strcmp(log_level_str, "fatal") || !strcmp(log_level_str, "FATAL"))
-		level = RATS_TLS_LOG_LEVEL_FATAL;
-	else if (!strcmp(log_level_str, "off") || !strcmp(log_level_str, "OFF"))
-		level = RATS_TLS_LOG_LEVEL_NONE;
-
-	free(log_level_str);
-
-	return level;
+	return RATS_TLS_LOG_LEVEL_DEFAULT;
 }
 
 rats_tls_err_t rtls_instance_init(const char *name, __attribute__((unused)) const char *realpath,
@@ -197,25 +203,23 @@ void rtls_exit(void)
 	exit(EXIT_FAILURE);
 }
 
-rats_tls_log_level_t get_loglevel_env(const char *name)
+rats_tls_log_level_t rtls_loglevel_getenv(const char *name)
 {
-	char *log_level_str = getenv(name);
-
-	if (!log_level_str)
-		return RATS_TLS_LOG_LEVEL_DEFAULT;
-
-	if (!strcasecmp(log_level_str, "debug"))
-		return RATS_TLS_LOG_LEVEL_DEBUG;
-	else if (!strcasecmp(log_level_str, "info"))
-		return RATS_TLS_LOG_LEVEL_INFO;
-	else if (!strcasecmp(log_level_str, "warn"))
-		return RATS_TLS_LOG_LEVEL_WARN;
-	else if (!strcasecmp(log_level_str, "error"))
-		return RATS_TLS_LOG_LEVEL_ERROR;
-	else if (!strcasecmp(log_level_str, "fatal"))
-		return RATS_TLS_LOG_LEVEL_FATAL;
-	else if (!strcasecmp(log_level_str, "off"))
-		return RATS_TLS_LOG_LEVEL_NONE;
+	char *log_level_str = log_level_str = getenv(name);
+	if (log_level_str) {
+		if (!strcasecmp(log_level_str, "debug"))
+			return RATS_TLS_LOG_LEVEL_DEBUG;
+		else if (!strcasecmp(log_level_str, "info"))
+			return RATS_TLS_LOG_LEVEL_INFO;
+		else if (!strcasecmp(log_level_str, "warn"))
+			return RATS_TLS_LOG_LEVEL_WARN;
+		else if (!strcasecmp(log_level_str, "error"))
+			return RATS_TLS_LOG_LEVEL_ERROR;
+		else if (!strcasecmp(log_level_str, "fatal"))
+			return RATS_TLS_LOG_LEVEL_FATAL;
+		else if (!strcasecmp(log_level_str, "off"))
+			return RATS_TLS_LOG_LEVEL_NONE;
+	}
 
 	return RATS_TLS_LOG_LEVEL_DEFAULT;
 }
diff --git a/src/core/rtls_core_generate_certificate.c b/src/core/rtls_core_generate_certificate.c
index b20db41..a4aa2c8 100644
--- a/src/core/rtls_core_generate_certificate.c
+++ b/src/core/rtls_core_generate_certificate.c
@@ -10,6 +10,7 @@
 #include "internal/attester.h"
 #include "internal/verifier.h"
 #include "internal/dice.h"
+#include "rats-tls/nonce.h"
 #include <string.h>
 
 rats_tls_err_t rtls_core_generate_certificate(rtls_core_context_t *ctx)
@@ -21,10 +22,6 @@ rats_tls_err_t rtls_core_generate_certificate(rtls_core_context_t *ctx)
 	    !ctx->crypto_wrapper->opts->gen_cert)
 		return -RATS_TLS_ERR_INVALID;
 
-	/* Avoid re-generation of TLS certificates */
-	if (ctx->flags & RATS_TLS_CTX_FLAGS_CERT_CREATED)
-		return RATS_TLS_ERR_NONE;
-
 	/* Check whether the specified algorithm is supported.
 	 *
 	 * TODO: the supported algorithm list should be provided by a crypto
@@ -59,6 +56,15 @@ rats_tls_err_t rtls_core_generate_certificate(rtls_core_context_t *ctx)
 	if (c_err != CRYPTO_WRAPPER_ERR_NONE)
 		return c_err;
 
+	/* Get received nonce */
+	uint8_t nonce[MAX_NONCE_SIZE];
+	size_t nonce_size = sizeof(nonce);
+	tls_wrapper_err_t t_err;
+	t_err = ctx->tls_wrapper->opts->get_nonce(ctx->tls_wrapper, true, nonce, &nonce_size);
+	if (t_err != TLS_WRAPPER_ERR_NONE) {
+		return t_err;
+	}
+
 	/* Collect evidence */
 	attestation_evidence_t evidence;
 	memset(&evidence, 0, sizeof(attestation_evidence_t));
@@ -71,7 +77,7 @@ rats_tls_err_t rtls_core_generate_certificate(rtls_core_context_t *ctx)
 	RTLS_DEBUG("fill evidence user-data field with sha256 of claims_buffer\n");
 	/* Generate claims_buffer */
 	enclave_attester_err_t a_ret = dice_generate_claims_buffer(
-		HASH_ALGO_SHA256, hash, ctx->config.custom_claims, ctx->config.custom_claims_length,
+		HASH_ALGO_SHA256, hash, nonce, nonce_size, ctx->config.custom_claims, ctx->config.custom_claims_length,
 		&claims_buffer, &claims_buffer_size);
 	if (a_ret != ENCLAVE_ATTESTER_ERR_NONE) {
 		RTLS_DEBUG("generate claims_buffer failed. a_ret: %#x\n", a_ret);
@@ -110,13 +116,13 @@ rats_tls_err_t rtls_core_generate_certificate(rtls_core_context_t *ctx)
 		.endorsements_buffer_size = 0,
 	};
 
-	/* Get DICE evidence buffer.
-	 * This check is a workaround for the nullattester.
-	 * Note: For nullattester, we do not generate an evidence_buffer, nor do we generate evidence extension.
-	 */
-	if (evidence.type[0] == '\0')
-		RTLS_WARN("No evidence in certificate due to using nullattester\n");
-	else {
+	/* Get DICE evidence buffer */
+	/* This check is a workaround for the nullattester.
+	 * Note: For nullattester, we do not generate an evidence_buffer. nor do we generate evidence extension.  */
+	if (evidence.type[0] == '\0') {
+		RTLS_WARN(
+			"evidence type is empty, which is normal only when you are using nullattester.\n");
+	} else {
 		enclave_attester_err_t d_ret = dice_generate_evidence_buffer_with_tag(
 			&evidence, claims_buffer, claims_buffer_size, &cert_info.evidence_buffer,
 			&cert_info.evidence_buffer_size);
@@ -191,8 +197,5 @@ rats_tls_err_t rtls_core_generate_certificate(rtls_core_context_t *ctx)
 	if (cert_info.cert_buf)
 		free(cert_info.cert_buf);
 
-	/* Prevent from re-generation of TLS certificate */
-	ctx->flags |= RATS_TLS_CTX_FLAGS_CERT_CREATED;
-
 	return RATS_TLS_ERR_NONE;
 }
diff --git a/src/crypto_wrappers/internal/rtls_crypto_wrapper_load_all.c b/src/crypto_wrappers/internal/rtls_crypto_wrapper_load_all.c
index 0e805bb..450e958 100644
--- a/src/crypto_wrappers/internal/rtls_crypto_wrapper_load_all.c
+++ b/src/crypto_wrappers/internal/rtls_crypto_wrapper_load_all.c
@@ -42,23 +42,21 @@ rats_tls_err_t rtls_crypto_wrapper_load_all(void)
 	unsigned int total_loaded = 0;
 	rtls_dirent *ptr = NULL;
 	while (rtls_readdir(dir, &ptr) != 1) {
-		const char *d_name = ptr->d_name;
-
-		if (!strcmp(d_name, ".") || !strcmp(d_name, ".."))
+		if (!strcmp(ptr->d_name, ".") || !strcmp(ptr->d_name, "..")) {
 			continue;
-
-		if (strncmp(d_name + strlen(d_name) - strlen(PATTERN_SUFFIX), PATTERN_SUFFIX,
-			    strlen(PATTERN_SUFFIX)))
+		}
+		if (strncmp(ptr->d_name + strlen(ptr->d_name) - strlen(PATTERN_SUFFIX),
+			    PATTERN_SUFFIX, strlen(PATTERN_SUFFIX))) {
 			continue;
-
+		}
 #ifdef OCCLUM
 		/* Occlum can't identify the d_type of the file, always return DT_UNKNOWN */
-		if (strncmp(d_name + strlen(d_name) - strlen(PATTERN_SUFFIX), PATTERN_SUFFIX,
-			    strlen(PATTERN_SUFFIX)) == 0) {
+		if (strncmp(ptr->d_name + strlen(ptr->d_name) - strlen(PATTERN_SUFFIX),
+			    PATTERN_SUFFIX, strlen(PATTERN_SUFFIX)) == 0) {
 #else
 		if (ptr->d_type == DT_REG || ptr->d_type == DT_LNK) {
 #endif
-			if (rtls_crypto_wrapper_load_single(d_name) == RATS_TLS_ERR_NONE)
+			if (rtls_crypto_wrapper_load_single(ptr->d_name) == RATS_TLS_ERR_NONE)
 				++total_loaded;
 		}
 	}
diff --git a/src/include/internal/attester.h b/src/include/internal/attester.h
index 78ee0c6..8be2a6e 100644
--- a/src/include/internal/attester.h
+++ b/src/include/internal/attester.h
@@ -10,7 +10,9 @@
 #include <rats-tls/attester.h>
 #include "internal/core.h"
 
+#ifndef ENCLAVE_ATTESTERS_DIR
 #define ENCLAVE_ATTESTERS_DIR "/usr/local/lib/rats-tls/attesters/"
+#endif
 
 extern rats_tls_err_t rtls_enclave_attester_load_all(void);
 extern rats_tls_err_t rtls_enclave_attester_load_single(const char *);
diff --git a/src/include/internal/core.h b/src/include/internal/core.h
index 0edb573..4697968 100644
--- a/src/include/internal/core.h
+++ b/src/include/internal/core.h
@@ -41,6 +41,8 @@ extern rats_tls_err_t rtls_core_generate_certificate(rtls_core_context_t *);
 
 extern void rtls_exit(void);
 
+extern rats_tls_log_level_t rtls_loglevel_getenv(const char *name);
+
 extern rats_tls_err_t rtls_instance_init(const char *type, const char *realpath, void **handle);
 
 extern ssize_t rtls_write(int fd, const void *buf, size_t count);
diff --git a/src/include/internal/cpu.h b/src/include/internal/cpu.h
index 8bfebc2..0a21fc9 100644
--- a/src/include/internal/cpu.h
+++ b/src/include/internal/cpu.h
@@ -28,5 +28,6 @@ extern bool is_tdguest_supported(void);
 extern bool is_snpguest_supported(void);
 extern bool is_sevguest_supported(void);
 extern bool is_csvguest_supported(void);
+extern bool is_virtccaguest_supported(void);
 
 #endif /* _INTERNAL_CPU_H */
diff --git a/src/include/internal/crypto_wrapper.h b/src/include/internal/crypto_wrapper.h
index c155f4a..3f17d9b 100644
--- a/src/include/internal/crypto_wrapper.h
+++ b/src/include/internal/crypto_wrapper.h
@@ -10,7 +10,9 @@
 #include <rats-tls/crypto_wrapper.h>
 #include "internal/core.h"
 
+#ifndef CRYPTO_WRAPPERS_DIR
 #define CRYPTO_WRAPPERS_DIR "/usr/local/lib/rats-tls/crypto-wrappers/"
+#endif
 
 extern rats_tls_err_t rtls_crypto_wrapper_load_all(void);
 extern rats_tls_err_t rtls_crypto_wrapper_load_single(const char *);
diff --git a/src/include/internal/dice.h b/src/include/internal/dice.h
index ef1c220..6559b71 100644
--- a/src/include/internal/dice.h
+++ b/src/include/internal/dice.h
@@ -11,6 +11,7 @@
 #include <rats-tls/endorsement.h>
 #include <rats-tls/claim.h>
 #include <rats-tls/hash.h>
+#include <rats-tls/nonce.h>
 
 /* Intel TEE quote, including all SGX (both EPID and ECDSA) and TDX (ECDSA) quote types */
 #define OCBR_TAG_EVIDENCE_INTEL_TEE_QUOTE 60000
@@ -18,6 +19,7 @@
 #define OCBR_TAG_EVIDENCE_INTEL_TEE_REPORT 60001
 /* SGX report (legacy, generated by EREPORT) */
 #define OCBR_TAG_EVIDENCE_INTEL_SGX_LEGACY_REPORT 60002
+#define OCBR_TAG_EVIDENCE_VIRTCCA		  0x0f0629
 #define OCBR_TAG_EVIDENCE_SEV_SNP		  0x1a7504
 #define OCBR_TAG_EVIDENCE_SEV			  0x1a7505
 #define OCBR_TAG_EVIDENCE_CSV			  0x1a7506
@@ -39,6 +41,7 @@ int evidence_from_raw(const uint8_t *data, size_t size, uint64_t tag,
 
 enclave_attester_err_t
 dice_generate_claims_buffer(hash_algo_t pubkey_hash_algo, const uint8_t *pubkey_hash,
+				const unsigned char *nonce, size_t nonce_size, 
 			    const claim_t *custom_claims, size_t custom_claims_length,
 			    uint8_t **claims_buffer_out, size_t *claims_buffer_size_out);
 
@@ -65,6 +68,7 @@ dice_parse_endorsements_buffer_with_tag(const char *type, const uint8_t *endorse
 enclave_verifier_err_t
 dice_parse_claims_buffer(const uint8_t *claims_buffer, size_t claims_buffer_size,
 			 hash_algo_t *pubkey_hash_algo_out, uint8_t *pubkey_hash_out,
+			 uint8_t *nonce_out, size_t *nonce_size_out,
 			 claim_t **custom_claims_out, size_t *custom_claims_length_out);
 
 #endif
diff --git a/src/include/internal/tls_wrapper.h b/src/include/internal/tls_wrapper.h
index b5e2f94..3758cfd 100644
--- a/src/include/internal/tls_wrapper.h
+++ b/src/include/internal/tls_wrapper.h
@@ -10,7 +10,9 @@
 #include <rats-tls/tls_wrapper.h>
 #include "internal/core.h"
 
+#ifndef TLS_WRAPPERS_DIR
 #define TLS_WRAPPERS_DIR "/usr/local/lib/rats-tls/tls-wrappers/"
+#endif
 
 extern rats_tls_err_t rtls_tls_wrapper_load_all(void);
 extern rats_tls_err_t rtls_tls_wrapper_load_single(const char *);
diff --git a/src/include/internal/verifier.h b/src/include/internal/verifier.h
index 659e689..a2f99f7 100644
--- a/src/include/internal/verifier.h
+++ b/src/include/internal/verifier.h
@@ -10,7 +10,9 @@
 #include <rats-tls/verifier.h>
 #include "internal/core.h"
 
+#ifndef ENCLAVE_VERIFIERS_DIR
 #define ENCLAVE_VERIFIERS_DIR "/usr/local/lib/rats-tls/verifiers/"
+#endif
 
 extern rats_tls_err_t rtls_enclave_verifier_load_all(void);
 extern rats_tls_err_t rtls_enclave_verifier_load_single(const char *);
diff --git a/src/include/rats-tls/api.h b/src/include/rats-tls/api.h
index 557872a..8fbb0e2 100644
--- a/src/include/rats-tls/api.h
+++ b/src/include/rats-tls/api.h
@@ -100,6 +100,11 @@ typedef struct rtls_csv_evidence {
 	uint32_t policy_sz;
 } rtls_csv_evidence_t;
 
+typedef struct rtls_cca_evidence {
+	uint8_t *evidence;
+	uint32_t evidence_sz;
+} rtls_cca_evidence_t;
+
 /* The public_key, user_data_size and user_data are needed to include in hash. */
 typedef struct ehd {
 	void *public_key;
@@ -109,7 +114,7 @@ typedef struct ehd {
 	char *unhashed;
 } ehd_t;
 
-typedef enum { SGX_ECDSA = 1, TDX_ECDSA, CSV } enclave_evidence_type_t;
+typedef enum { SGX_ECDSA = 1, TDX_ECDSA, CSV, CCA } enclave_evidence_type_t;
 
 typedef struct rtls_evidence {
 	enclave_evidence_type_t type;
@@ -122,6 +127,7 @@ typedef struct rtls_evidence {
 		rtls_sgx_evidence_t sgx;
 		rtls_tdx_evidence_t tdx;
 		rtls_csv_evidence_t csv;
+		rtls_cca_evidence_t cca;
 	};
 } rtls_evidence_t;
 
diff --git a/src/include/rats-tls/attester.h b/src/include/rats-tls/attester.h
index e73472a..1bd96c7 100644
--- a/src/include/rats-tls/attester.h
+++ b/src/include/rats-tls/attester.h
@@ -20,11 +20,13 @@
 #define ENCLAVE_ATTESTER_API_VERSION_MAX     ENCLAVE_ATTESTER_API_VERSION_1
 #define ENCLAVE_ATTESTER_API_VERSION_DEFAULT ENCLAVE_ATTESTER_API_VERSION_1
 
-#define ENCLAVE_ATTESTER_OPTS_FLAGS_SGX_ENCLAVE (1 << 0)
-#define ENCLAVE_ATTESTER_OPTS_FLAGS_TDX_GUEST	(ENCLAVE_ATTESTER_OPTS_FLAGS_SGX_ENCLAVE << 1)
-#define ENCLAVE_ATTESTER_OPTS_FLAGS_SEV_GUEST	(ENCLAVE_ATTESTER_OPTS_FLAGS_TDX_GUEST << 1)
-#define ENCLAVE_ATTESTER_OPTS_FLAGS_SNP_GUEST	(ENCLAVE_ATTESTER_OPTS_FLAGS_SEV_GUEST << 1)
-#define ENCLAVE_ATTESTER_OPTS_FLAGS_CSV_GUEST	(ENCLAVE_ATTESTER_OPTS_FLAGS_SNP_GUEST << 1)
+#define ENCLAVE_ATTESTER_OPTS_FLAGS_SGX_ENCLAVE 	(1 << 0)
+#define ENCLAVE_ATTESTER_OPTS_FLAGS_TDX_GUEST		(ENCLAVE_ATTESTER_OPTS_FLAGS_SGX_ENCLAVE << 1)
+#define ENCLAVE_ATTESTER_OPTS_FLAGS_SEV_GUEST		(ENCLAVE_ATTESTER_OPTS_FLAGS_TDX_GUEST << 1)
+#define ENCLAVE_ATTESTER_OPTS_FLAGS_SNP_GUEST		(ENCLAVE_ATTESTER_OPTS_FLAGS_SEV_GUEST << 1)
+#define ENCLAVE_ATTESTER_OPTS_FLAGS_CSV_GUEST		(ENCLAVE_ATTESTER_OPTS_FLAGS_SNP_GUEST << 1)
+#define ENCLAVE_ATTESTER_OPTS_FLAGS_VIRTCCA_GUEST	(ENCLAVE_ATTESTER_OPTS_FLAGS_CSV_GUEST << 1)
+#define ENCLAVE_ATTESTER_OPTS_FLAGS_VIRTCCA_FAKE	(ENCLAVE_ATTESTER_OPTS_FLAGS_VIRTCCA_GUEST << 1)
 
 #define ENCLAVE_ATTESTER_FLAGS_DEFAULT 0
 
@@ -78,6 +80,12 @@ struct enclave_attester_ctx {
 			const char name[ENCLAVE_ATTESTER_TYPE_NAME_SIZE];
 			uint8_t cert_type;
 		} tdx;
+
+		struct {
+			const char name[ENCLAVE_ATTESTER_TYPE_NAME_SIZE];
+			// Fixme: Add here
+		} virtcca;
+		
 	} config;
 };
 
diff --git a/src/include/rats-tls/cert.h b/src/include/rats-tls/cert.h
index 2706696..d59b478 100644
--- a/src/include/rats-tls/cert.h
+++ b/src/include/rats-tls/cert.h
@@ -7,6 +7,8 @@
 #ifndef _ENCLAVE_CERT_H
 #define _ENCLAVE_CERT_H
 
+#define REPORT_MAX_LENGTH 8192
+
 typedef struct {
 	const unsigned char *organization;
 	const unsigned char *organization_unit;
@@ -54,6 +56,11 @@ typedef struct {
 	uint32_t report_len;
 } csv_attestation_evidence_t;
 
+typedef struct {
+	uint8_t report[REPORT_MAX_LENGTH];  // 8bytes report_len + report + 8bytes device_cert_len + device_cert
+	uint32_t report_len;
+} virtcca_attestation_evidence_t;
+
 typedef struct {
 	char type[ENCLAVE_ATTESTER_TYPE_NAME_SIZE];
 	union {
@@ -64,6 +71,7 @@ typedef struct {
 		snp_attestation_evidence_t snp;
 		sev_attestation_evidence_t sev;
 		csv_attestation_evidence_t csv;
+		virtcca_attestation_evidence_t virtcca;
 	};
 } attestation_evidence_t;
 
diff --git a/src/include/rats-tls/err.h b/src/include/rats-tls/err.h
index 359e8eb..c01c8ed 100644
--- a/src/include/rats-tls/err.h
+++ b/src/include/rats-tls/err.h
@@ -116,6 +116,7 @@ typedef enum {
 	TLS_WRAPPER_ERR_UNSUPPORTED_QUOTE,
 	TLS_WRAPPER_ERR_PRIV_KEY,
 	TLS_WRAPPER_ERR_CERT,
+	TLS_WRAPPER_ERR_NONCE,
 	TLS_WRAPPER_ERR_UNKNOWN,
 } tls_wrapper_err_t;
 
diff --git a/src/include/rats-tls/log.h b/src/include/rats-tls/log.h
index 9edb201..6895b50 100644
--- a/src/include/rats-tls/log.h
+++ b/src/include/rats-tls/log.h
@@ -61,6 +61,14 @@ extern rats_tls_log_level_t global_log_level;
 			printf("[" #level "] %s()@L%d: " fmt, __FUNCTION__, __LINE__, \
 			       ##__VA_ARGS__);                                        \
 	} while (0)
+#elif defined VIRTCCA
+  #define __PR__(level, io, fmt, ...)                                                   \
+	do {                                                                          \
+		if (global_log_level <= RATS_TLS_LOG_LEVEL_##level)               \
+			printf("[" #level "] %s()@L%d: " fmt, __FUNCTION__, __LINE__, \
+			       ##__VA_ARGS__);                                        \
+			fflush(io); 												  \
+	} while (0)
 #else
   #define __PR__(level, io, fmt, ...)                                                   \
 	do {                                                                            \
diff --git a/src/include/rats-tls/nonce.h b/src/include/rats-tls/nonce.h
new file mode 100644
index 0000000..82c2999
--- /dev/null
+++ b/src/include/rats-tls/nonce.h
@@ -0,0 +1,6 @@
+#ifndef _RATS_TLS_NONCE_H
+#define _RATS_TLS_NONCE_H
+
+#define MAX_NONCE_SIZE 64
+
+#endif /* _RATS_TLS_NONCE_H */
\ No newline at end of file
diff --git a/src/include/rats-tls/tls_wrapper.h b/src/include/rats-tls/tls_wrapper.h
index 32ad442..5e7d42d 100644
--- a/src/include/rats-tls/tls_wrapper.h
+++ b/src/include/rats-tls/tls_wrapper.h
@@ -36,6 +36,7 @@ typedef struct {
 	tls_wrapper_err_t (*use_privkey)(tls_wrapper_ctx_t *ctx, rats_tls_cert_algo_t algo,
 					 void *privkey_buf, size_t privkey_len);
 	tls_wrapper_err_t (*use_cert)(tls_wrapper_ctx_t *ctx, rats_tls_cert_info_t *cert_info);
+	tls_wrapper_err_t (*get_nonce)(tls_wrapper_ctx_t *ctx, bool peer, void *buf, size_t *buf_size);
 	tls_wrapper_err_t (*negotiate)(tls_wrapper_ctx_t *ctx, int fd);
 	tls_wrapper_err_t (*transmit)(tls_wrapper_ctx_t *ctx, void *buf, size_t *buf_size);
 	tls_wrapper_err_t (*receive)(tls_wrapper_ctx_t *ctx, void *buf, size_t *buf_size);
@@ -57,7 +58,8 @@ extern tls_wrapper_err_t tls_wrapper_register(const tls_wrapper_opts_t *);
 
 extern tls_wrapper_err_t
 tls_wrapper_verify_certificate_extension(tls_wrapper_ctx_t *tls_ctx, const uint8_t *pubkey_buffer,
-					 size_t pubkey_buffer_size, uint8_t *evidence_buffer,
+					 size_t pubkey_buffer_size, const uint8_t *nonce_buffer,
+					 size_t nonce_buffer_size, uint8_t *evidence_buffer,
 					 size_t evidence_buffer_size, uint8_t *endorsements_buffer,
 					 size_t endorsements_buffer_size);
 
diff --git a/src/include/rats-tls/verifier.h b/src/include/rats-tls/verifier.h
index be891e9..4041841 100644
--- a/src/include/rats-tls/verifier.h
+++ b/src/include/rats-tls/verifier.h
@@ -23,10 +23,11 @@
 #define ENCLAVE_VERIFIER_OPTS_FLAGS_DEFAULT	 0
 #define ENCLAVE_VERIFIER_OPTS_FLAGS_SGX1_ENCLAVE (1 << 0)
 #define ENCLAVE_VERIFIER_OPTS_FLAGS_SGX2_ENCLAVE (1 << 1)
-#define ENCLAVE_VERIFIER_OPTS_FLAGS_TDX		 (1 << 2)
-#define ENCLAVE_VERIFIER_OPTS_FLAGS_SNP		 (1 << 3)
-#define ENCLAVE_VERIFIER_OPTS_FLAGS_SEV		 (1 << 4)
-#define ENCLAVE_VERIFIER_OPTS_FLAGS_CSV		 (1 << 5)
+#define ENCLAVE_VERIFIER_OPTS_FLAGS_TDX		 	 (1 << 2)
+#define ENCLAVE_VERIFIER_OPTS_FLAGS_SNP		 	 (1 << 3)
+#define ENCLAVE_VERIFIER_OPTS_FLAGS_SEV		 	 (1 << 4)
+#define ENCLAVE_VERIFIER_OPTS_FLAGS_CSV		 	 (1 << 5)
+#define ENCLAVE_VERIFIER_OPTS_FLAGS_VIRTCCA		 (1 << 6)
 
 typedef struct enclave_verifier_ctx enclave_verifier_ctx_t;
 
@@ -72,6 +73,11 @@ struct enclave_verifier_ctx {
 			const char name[ENCLAVE_VERIFIER_TYPE_NAME_SIZE];
 			uint8_t cert_type;
 		} tdx;
+
+		struct {
+			const char name[ENCLAVE_VERIFIER_TYPE_NAME_SIZE];
+			// FixMe: add here
+		} virtcca;
 	} config;
 };
 
diff --git a/src/tls_wrappers/api/tls_wrapper_verify_certificate_extension.c b/src/tls_wrappers/api/tls_wrapper_verify_certificate_extension.c
index e1a70e6..50c61e3 100644
--- a/src/tls_wrappers/api/tls_wrapper_verify_certificate_extension.c
+++ b/src/tls_wrappers/api/tls_wrapper_verify_certificate_extension.c
@@ -14,11 +14,13 @@
 #include "internal/dice.h"
 
 #include <rats-tls/csv.h>
+#include <rats-tls/virtcca.h>
 // clang-format off
 #ifdef SGX
 #include "sgx_report.h"
 #endif
-#include "sgx_quote_3.h"
+// FixMe: "sgx_quote_3.h"
+// #include "sgx_quote_3.h"
 // clang-format on
 
 tls_wrapper_err_t
@@ -34,26 +36,17 @@ tls_wrapper_verify_evidence(tls_wrapper_ctx_t *tls_ctx, attestation_evidence_t *
 	    !tls_ctx->rtls_handle->verifier->opts->verify_evidence)
 		return -TLS_WRAPPER_ERR_INVALID;
 
-	if (!(tls_ctx->rtls_handle->flags & RATS_TLS_CONF_FLAGS_VERIFIER_ENFORCED)) {
-		char *type;
-
-		if (evidence->type[0])
-			type = evidence->type;
-		else
-			type = "nullverifier";
-
-		if (strcmp(tls_ctx->rtls_handle->verifier->opts->type, type)) {
-			RTLS_DEBUG("Requesting verifier '%s' against current verifier '%s'\n", type,
-				   tls_ctx->rtls_handle->verifier->opts->name);
-
-			rats_tls_err_t tlserr = rtls_verifier_select(
-				tls_ctx->rtls_handle, type, tls_ctx->rtls_handle->config.cert_algo);
-			if (tlserr != RATS_TLS_ERR_NONE) {
-				RTLS_ERR(
-					"the verifier selecting err %#x during verifying cert extension\n",
-					tlserr);
-				return -TLS_WRAPPER_ERR_INVALID;
-			}
+	if (strcmp(tls_ctx->rtls_handle->verifier->opts->type, evidence->type) &&
+	    !(tls_ctx->rtls_handle->flags & RATS_TLS_CONF_FLAGS_VERIFIER_ENFORCED)) {
+		RTLS_WARN("type doesn't match between verifier '%s' and evidence '%s'\n",
+			  tls_ctx->rtls_handle->verifier->opts->name, evidence->type);
+		rats_tls_err_t tlserr =
+			rtls_verifier_select(tls_ctx->rtls_handle, evidence->type,
+					     tls_ctx->rtls_handle->config.cert_algo);
+		if (tlserr != RATS_TLS_ERR_NONE) {
+			RTLS_ERR("the verifier selecting err %#x during verifying cert extension\n",
+				 tlserr);
+			return -TLS_WRAPPER_ERR_INVALID;
 		}
 	}
 
@@ -70,7 +63,10 @@ tls_wrapper_verify_evidence(tls_wrapper_ctx_t *tls_ctx, attestation_evidence_t *
 tls_wrapper_err_t tls_wrapper_verify_certificate_extension(
 	tls_wrapper_ctx_t *tls_ctx,
 	const uint8_t *pubkey_buffer /* in SubjectPublicKeyInfo format */,
-	size_t pubkey_buffer_size, uint8_t *evidence_buffer /* optional, for nullverifier */,
+	size_t pubkey_buffer_size, 
+	const uint8_t *nonce_buffer,
+	size_t nonce_buffer_size,
+	uint8_t *evidence_buffer /* optional, for nullverifier */,
 	size_t evidence_buffer_size, uint8_t *endorsements_buffer /* optional */,
 	size_t endorsements_buffer_size)
 {
@@ -84,19 +80,20 @@ tls_wrapper_err_t tls_wrapper_verify_certificate_extension(
 	size_t custom_claims_length = 0;
 
 	RTLS_DEBUG(
-		"tls_ctx: %p, pubkey_buffer: %p, pubkey_buffer_size: %zu, evidence_buffer: %p, evidence_buffer_size: %zu, endorsements_buffer: %p, endorsements_buffer_size: %zu\n",
-		tls_ctx, pubkey_buffer, pubkey_buffer_size, evidence_buffer, evidence_buffer_size,
+		"tls_ctx: %p, pubkey_buffer: %p, pubkey_buffer_size: %zu, nonce_buffer: %p, nonce_buffer_size: %zu, "
+		"evidence_buffer: %p, evidence_buffer_size: %zu, endorsements_buffer: %p, endorsements_buffer_size: %zu\n",
+		tls_ctx, pubkey_buffer, pubkey_buffer_size, nonce_buffer, nonce_buffer_size, evidence_buffer, evidence_buffer_size,
 		endorsements_buffer, endorsements_buffer_size);
 
 	if (!tls_ctx || !tls_ctx->rtls_handle || !tls_ctx->rtls_handle->verifier ||
 	    !tls_ctx->rtls_handle->verifier->opts ||
-	    !tls_ctx->rtls_handle->verifier->opts->verify_evidence || !pubkey_buffer)
+	    !tls_ctx->rtls_handle->verifier->opts->verify_evidence || !pubkey_buffer || !nonce_buffer)
 		return -TLS_WRAPPER_ERR_INVALID;
 
 	/* Get evidence struct and claims_buffer from evidence_buffer. */
 	if (!evidence_buffer) {
 		/* evidence_buffer is empty, which means that the other party is using a non-dice certificate or is using a nullattester */
-		RTLS_WARN("No evidence available in peer's certificate\n");
+		RTLS_WARN("there is no evidence buffer in peer's certificate.\n");
 		memset(&evidence, 0, sizeof(attestation_evidence_t));
 	} else {
 		enclave_verifier_err_t d_ret = dice_parse_evidence_buffer_with_tag(
@@ -179,9 +176,11 @@ tls_wrapper_err_t tls_wrapper_verify_certificate_extension(
 	if (claims_buffer) {
 		hash_algo_t pubkey_hash_algo = HASH_ALGO_RESERVED;
 		uint8_t pubkey_hash[MAX_HASH_SIZE];
+		uint8_t nonce[MAX_NONCE_SIZE];
+		size_t nonce_size = 0;
 		enclave_verifier_err_t d_ret = dice_parse_claims_buffer(
 			claims_buffer, claims_buffer_size, &pubkey_hash_algo, pubkey_hash,
-			&custom_claims, &custom_claims_length);
+			nonce, &nonce_size, &custom_claims, &custom_claims_length);
 		free(claims_buffer);
 		claims_buffer = NULL;
 		if (d_ret != ENCLAVE_VERIFIER_ERR_NONE) {
@@ -229,6 +228,25 @@ tls_wrapper_err_t tls_wrapper_verify_certificate_extension(
 			ret = TLS_WRAPPER_ERR_INVALID;
 			goto err;
 		}
+
+		/* Verify nonce */
+		RTLS_DEBUG("check nonce. nonce_buffer_size: %zu, nonce size: %zu\n", nonce_buffer_size, nonce_size);
+		RTLS_DEBUG("The nonce in claim [%zu] %02x%02x%02x%02x%02x%02x%02x%02x...\n",
+			   nonce_size, nonce[0], nonce[1], nonce[2], nonce[3],
+			   nonce[4], nonce[5], nonce[6], nonce[7]);
+
+		if (nonce_buffer_size != nonce_size) {
+			RTLS_ERR("unmatched nonce lenth in claims buffer\n");
+			ret = TLS_WRAPPER_ERR_INVALID;
+			goto err;
+		}
+		
+		if (memcmp(nonce_buffer, nonce, nonce_buffer_size)) {
+			RTLS_ERR("unmatched nonce value in claims buffer\n");
+			ret = TLS_WRAPPER_ERR_INVALID;
+			goto err;
+		} 
+
 	}
 
 	/* Verify evidence struct via user_callback */
@@ -237,16 +255,17 @@ tls_wrapper_err_t tls_wrapper_verify_certificate_extension(
 	ev.custom_claims = custom_claims;
 	ev.custom_claims_length = custom_claims_length;
 	if (!strncmp(evidence.type, "sgx_ecdsa", sizeof(evidence.type))) {
-		sgx_quote3_t *quote3 = (sgx_quote3_t *)evidence.ecdsa.quote;
-
-		ev.sgx.mr_enclave = (uint8_t *)quote3->report_body.mr_enclave.m;
-		ev.sgx.mr_signer = quote3->report_body.mr_signer.m;
-		ev.sgx.product_id = quote3->report_body.isv_prod_id;
-		ev.sgx.security_version = quote3->report_body.isv_svn;
-		ev.sgx.attributes = (uint8_t *)&(quote3->report_body.attributes);
-		ev.type = SGX_ECDSA;
-		ev.quote = (char *)quote3;
-		ev.quote_size = sizeof(sgx_quote3_t);
+		// FixMe: "sgx_quote_3.h"
+		// sgx_quote3_t *quote3 = (sgx_quote3_t *)evidence.ecdsa.quote;
+
+		// ev.sgx.mr_enclave = (uint8_t *)quote3->report_body.mr_enclave.m;
+		// ev.sgx.mr_signer = quote3->report_body.mr_signer.m;
+		// ev.sgx.product_id = quote3->report_body.isv_prod_id;
+		// ev.sgx.security_version = quote3->report_body.isv_svn;
+		// ev.sgx.attributes = (uint8_t *)&(quote3->report_body.attributes);
+		// ev.type = SGX_ECDSA;
+		// ev.quote = (char *)quote3;
+		// ev.quote_size = sizeof(sgx_quote3_t);
 	}
 #if 0
 	else if (!strncmp(evidence.type, "tdx_ecdsa", sizeof(evidence.type))) {
@@ -284,6 +303,12 @@ tls_wrapper_err_t tls_wrapper_verify_certificate_extension(
 		ev.quote_size = sizeof(*report);
 	}
 
+	else if (!strncmp(evidence.type, "virtcca", sizeof(evidence.type))) {
+		ev.cca.evidence = (uint8_t *)tls_ctx->rtls_handle->verifier->verifier_private;
+		ev.cca.evidence_sz = 4104;
+		ev.type = CCA;
+	}
+
 	if (tls_ctx->rtls_handle->user_callback) {
 		int rc = tls_ctx->rtls_handle->user_callback(&ev);
 		if (!rc) {
diff --git a/src/tls_wrappers/nulltls/negotiate.c b/src/tls_wrappers/nulltls/negotiate.c
index 028d78e..b9b6a66 100644
--- a/src/tls_wrappers/nulltls/negotiate.c
+++ b/src/tls_wrappers/nulltls/negotiate.c
@@ -22,8 +22,10 @@ tls_wrapper_err_t nulltls_negotiate(tls_wrapper_ctx_t *ctx, int fd)
 
 		size_t pubkey_buffer_size = 0;
 		uint8_t pubkey_buffer[pubkey_buffer_size];
+		size_t nonce_buffer_size = 0;
+		uint8_t nonce_buffer[nonce_buffer_size];
 		tls_wrapper_err_t err = tls_wrapper_verify_certificate_extension(
-			ctx, pubkey_buffer, pubkey_buffer_size, NULL, 0, NULL, 0);
+			ctx, pubkey_buffer, pubkey_buffer_size, nonce_buffer, nonce_buffer_size, NULL, 0, NULL, 0);
 		if (err != TLS_WRAPPER_ERR_NONE) {
 			RTLS_ERR("ERROR: failed to verify certificate extension\n");
 			return err;
diff --git a/src/tls_wrappers/nulltls/receive.c b/src/tls_wrappers/nulltls/receive.c
index fd0ea12..86ee259 100644
--- a/src/tls_wrappers/nulltls/receive.c
+++ b/src/tls_wrappers/nulltls/receive.c
@@ -6,8 +6,8 @@
 
 #include <unistd.h>
 #include <rats-tls/log.h>
+#include <internal/core.h>
 #include <rats-tls/tls_wrapper.h>
-#include "internal/core.h"
 
 tls_wrapper_err_t nulltls_receive(tls_wrapper_ctx_t *ctx, void *buf, size_t *buf_size)
 {
diff --git a/src/tls_wrappers/nulltls/transmit.c b/src/tls_wrappers/nulltls/transmit.c
index e450679..08f16e0 100644
--- a/src/tls_wrappers/nulltls/transmit.c
+++ b/src/tls_wrappers/nulltls/transmit.c
@@ -7,7 +7,7 @@
 #include <unistd.h>
 #include <rats-tls/log.h>
 #include <rats-tls/tls_wrapper.h>
-#include "internal/core.h"
+#include <internal/core.h>
 
 tls_wrapper_err_t nulltls_transmit(tls_wrapper_ctx_t *ctx, void *buf, size_t *buf_size)
 {
diff --git a/src/tls_wrappers/openssl/CMakeLists.txt b/src/tls_wrappers/openssl/CMakeLists.txt
index 2bc8da8..bb7900d 100644
--- a/src/tls_wrappers/openssl/CMakeLists.txt
+++ b/src/tls_wrappers/openssl/CMakeLists.txt
@@ -27,6 +27,7 @@ set(SOURCES cleanup.c
             receive.c
             transmit.c
             use_cert.c
+            get_nonce.c
             use_privkey.c
             x509_openssl10x.c
             )
diff --git a/src/tls_wrappers/openssl/get_nonce.c b/src/tls_wrappers/openssl/get_nonce.c
new file mode 100644
index 0000000..ed7de05
--- /dev/null
+++ b/src/tls_wrappers/openssl/get_nonce.c
@@ -0,0 +1,49 @@
+#include <rats-tls/log.h>
+#include <rats-tls/tls_wrapper.h>
+#include "openssl.h"
+#include <string.h>
+
+tls_wrapper_err_t openssl_tls_get_nonce(tls_wrapper_ctx_t *ctx, bool peer, void *buf, size_t *buf_size)
+{
+    RTLS_DEBUG("ctx: %p, peer: %d, buf: %p, buf_size: %zu\n", ctx, peer, buf, *buf_size);
+    size_t len;
+
+	if (!ctx || !buf || !buf_size)
+		return -TLS_WRAPPER_ERR_INVALID;
+
+    unsigned char *buffer = (unsigned char *)buf;
+	openssl_ctx_t *ssl_ctx = (openssl_ctx_t *)ctx->tls_private;
+	if (ssl_ctx == NULL || ssl_ctx->ssl == NULL) {
+        RTLS_ERR("no ssl_ctx or ssl available\n");
+        return -TLS_WRAPPER_ERR_NONCE; 
+    }
+	
+    /* Read self or peer random number
+       SERVER && peer=True  : client
+       CLIENT && peer=False : client
+       SERVER && peer=False : server
+       CLIENT && peer=True  : server
+    */
+    unsigned long conf_flags = ctx->conf_flags;
+    if (((conf_flags & RATS_TLS_CONF_FLAGS_SERVER) && peer) ||
+        (!(conf_flags & RATS_TLS_CONF_FLAGS_SERVER) && !peer)) {
+        len = SSL_get_client_random(ssl_ctx->ssl, buffer, *buf_size);
+    } else {
+        len = SSL_get_server_random(ssl_ctx->ssl, buffer, *buf_size);
+    }
+
+    /* len can only be smaller or equal to buf_size */
+    *buf_size = len;
+
+    if (len > 0) {
+		RTLS_DEBUG(
+			"%s random number in hello [%zu] %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x...\n",
+			peer ? "peer" : "self", *buf_size, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], 
+            buffer[6],	buffer[7], buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15]);
+    } else {
+        RTLS_ERR("SSL_get_*_random() failed\n");
+        return TLS_WRAPPER_ERR_NONCE;
+    }
+
+    return TLS_WRAPPER_ERR_NONE;
+}
\ No newline at end of file
diff --git a/src/tls_wrappers/openssl/main.c b/src/tls_wrappers/openssl/main.c
index c1c88fe..b108aa6 100644
--- a/src/tls_wrappers/openssl/main.c
+++ b/src/tls_wrappers/openssl/main.c
@@ -15,6 +15,8 @@ extern tls_wrapper_err_t openssl_tls_use_privkey(tls_wrapper_ctx_t *ctx, rats_tl
 						 void *privkey_buf, size_t privkey_len);
 extern tls_wrapper_err_t openssl_tls_use_cert(tls_wrapper_ctx_t *ctx,
 					      rats_tls_cert_info_t *cert_info);
+extern tls_wrapper_err_t openssl_tls_get_nonce(tls_wrapper_ctx_t *ctx, bool peer, 
+						  void *buf, size_t *buf_size);
 extern tls_wrapper_err_t openssl_tls_negotiate(tls_wrapper_ctx_t *, int fd);
 extern tls_wrapper_err_t openssl_tls_transmit(tls_wrapper_ctx_t *, void *, size_t *);
 extern tls_wrapper_err_t openssl_tls_receive(tls_wrapper_ctx_t *, void *, size_t *);
@@ -28,6 +30,7 @@ static tls_wrapper_opts_t openssl_opts = {
 	.init = openssl_tls_init,
 	.use_privkey = openssl_tls_use_privkey,
 	.use_cert = openssl_tls_use_cert,
+	.get_nonce = openssl_tls_get_nonce,
 	.negotiate = openssl_tls_negotiate,
 	.transmit = openssl_tls_transmit,
 	.receive = openssl_tls_receive,
diff --git a/src/tls_wrappers/openssl/negotiate.c b/src/tls_wrappers/openssl/negotiate.c
index 8657924..bee95c1 100644
--- a/src/tls_wrappers/openssl/negotiate.c
+++ b/src/tls_wrappers/openssl/negotiate.c
@@ -11,6 +11,7 @@
 #include "openssl.h"
 
 extern int verify_certificate(int preverify_ok, X509_STORE_CTX *store);
+extern int generate_certificate(SSL *ssl, void *ctx);
 
 tls_wrapper_err_t openssl_internal_negotiate(tls_wrapper_ctx_t *ctx, unsigned long conf_flags,
 					     int fd, int (*verify)(int, X509_STORE_CTX *))
@@ -37,9 +38,13 @@ tls_wrapper_err_t openssl_internal_negotiate(tls_wrapper_ctx_t *ctx, unsigned lo
 		SSL_CTX_set_verify(ssl_ctx->sctx, mode, verify);
 	}
 
+	/* Set certificate callback function to dynamically generate certificate */
+	SSL_CTX_set_cert_cb(ssl_ctx->sctx, generate_certificate, (void *) ctx);
+
 	SSL *ssl = SSL_new(ssl_ctx->sctx);
 	if (!ssl)
 		return -TLS_WRAPPER_ERR_NO_MEM;
+	ssl_ctx->ssl = ssl;
 
 	X509_STORE *cert_store = SSL_CTX_get_cert_store(ssl_ctx->sctx);
 	X509_STORE_set_ex_data(cert_store, openssl_ex_data_idx, ctx);
@@ -67,12 +72,10 @@ tls_wrapper_err_t openssl_internal_negotiate(tls_wrapper_ctx_t *ctx, unsigned lo
 				 SSL_get_error(ssl, err));
 		// TODO: handle result of SSL_get_error()
 		print_openssl_err_all(ssl, err);
-
+		ssl_ctx->ssl = NULL;
 		return OPENSSL_ERR_CODE(err);
 	}
 
-	ssl_ctx->ssl = ssl;
-
 	if (conf_flags & RATS_TLS_CONF_FLAGS_SERVER)
 		RTLS_DEBUG("success to negotiate\n");
 	else
diff --git a/src/tls_wrappers/openssl/un_negotiate.c b/src/tls_wrappers/openssl/un_negotiate.c
index 20acd4f..2ef86df 100644
--- a/src/tls_wrappers/openssl/un_negotiate.c
+++ b/src/tls_wrappers/openssl/un_negotiate.c
@@ -9,9 +9,11 @@
 #include <rats-tls/log.h>
 #include <rats-tls/err.h>
 #include <rats-tls/tls_wrapper.h>
+#include <internal/core.h>
+#include <internal/dice.h>
 #include "openssl.h"
-#include "internal/core.h"
-#include "internal/dice.h"
+
+extern tls_wrapper_err_t openssl_tls_get_nonce(tls_wrapper_ctx_t *ctx, bool peer, void *buf, size_t *buf_size);
 
 static int rtls_memcpy_s(void *dst, uint32_t dst_size, const void *src, uint32_t num_bytes)
 {
@@ -199,6 +201,8 @@ int verify_certificate(int preverify_ok, X509_STORE_CTX *ctx)
 		return 0;
 	}
 
+	tls_wrapper_err_t t_err;
+
 	/* Get pubkey in SubjectPublicKeyInfo format from cert */
 	EVP_PKEY *pkey = X509_get_pubkey(cert);
 	if (!pkey) {
@@ -211,6 +215,16 @@ int verify_certificate(int preverify_ok, X509_STORE_CTX *ctx)
 	i2d_PUBKEY(pkey, &p);
 	EVP_PKEY_free(pkey);
 
+	/* Get nonce from sent hello */
+	uint8_t nonce_buffer[MAX_NONCE_SIZE];
+	size_t nonce_buffer_size = sizeof(nonce_buffer);
+
+	t_err = openssl_tls_get_nonce(tls_ctx, false, nonce_buffer, &nonce_buffer_size);
+	if (t_err != TLS_WRAPPER_ERR_NONE) {
+		RTLS_ERR("faild to get sent nonce %#x\n", t_err);
+		return 0;
+	}
+
 	/* Extract the RATS-TLS certificate evidence_buffer(optional for nullverifier) and endorsements_buffer(optional) from the TLS
 	 * certificate extension.
 	 */
@@ -235,8 +249,9 @@ int verify_certificate(int preverify_ok, X509_STORE_CTX *ctx)
 		return rc;
 	}
 
-	tls_wrapper_err_t t_err = tls_wrapper_verify_certificate_extension(
-		tls_ctx, pubkey_buffer, pubkey_buffer_size, evidence_buffer, evidence_buffer_size,
+	t_err = tls_wrapper_verify_certificate_extension(
+		tls_ctx, pubkey_buffer, pubkey_buffer_size, nonce_buffer, nonce_buffer_size,
+		evidence_buffer, evidence_buffer_size,
 		endorsements_buffer, endorsements_buffer_size);
 	if (t_err != TLS_WRAPPER_ERR_NONE) {
 		RTLS_ERR("failed to verify certificate extension %#x\n", t_err);
@@ -245,3 +260,18 @@ int verify_certificate(int preverify_ok, X509_STORE_CTX *ctx)
 
 	return SSL_SUCCESS;
 }
+
+int generate_certificate(SSL *ssl, void *ctx)
+{
+    RTLS_DEBUG("ssl: %p, ctx: %p\n", ssl, ctx);
+    rats_tls_err_t err;
+    tls_wrapper_ctx_t *ctx_tls = (tls_wrapper_ctx_t *) ctx; 
+
+	err = rtls_core_generate_certificate(ctx_tls->rtls_handle);
+	if (err != RATS_TLS_ERR_NONE){
+		return 0;
+	}
+
+	return 1;
+
+}
\ No newline at end of file
diff --git a/src/tls_wrappers/openssl/use_cert.c b/src/tls_wrappers/openssl/use_cert.c
index 768295d..d65d733 100644
--- a/src/tls_wrappers/openssl/use_cert.c
+++ b/src/tls_wrappers/openssl/use_cert.c
@@ -16,8 +16,8 @@ tls_wrapper_err_t openssl_tls_use_cert(tls_wrapper_ctx_t *ctx, rats_tls_cert_inf
 		return -TLS_WRAPPER_ERR_INVALID;
 
 	openssl_ctx_t *ssl_ctx = (openssl_ctx_t *)ctx->tls_private;
-	int ret = SSL_CTX_use_certificate_ASN1(ssl_ctx->sctx, cert_info->cert_len,
-					       cert_info->cert_buf);
+	int ret = SSL_use_certificate_ASN1(ssl_ctx->ssl, 
+					       cert_info->cert_buf, cert_info->cert_len);
 	if (ret != SSL_SUCCESS) {
 		RTLS_ERR("failed to use certificate %d\n", ret);
 		return OPENSSL_ERR_CODE(ret);
diff --git a/src/tls_wrappers/openssl/use_privkey.c b/src/tls_wrappers/openssl/use_privkey.c
index 447f253..ca2928e 100644
--- a/src/tls_wrappers/openssl/use_privkey.c
+++ b/src/tls_wrappers/openssl/use_privkey.c
@@ -28,7 +28,7 @@ tls_wrapper_err_t openssl_tls_use_privkey(tls_wrapper_ctx_t *ctx, rats_tls_cert_
 		return -CRYPTO_WRAPPER_ERR_UNSUPPORTED_ALGO;
 	}
 
-	int ret = SSL_CTX_use_PrivateKey_ASN1(EPKEY, ssl_ctx->sctx, privkey_buf, (long)privkey_len);
+	int ret = SSL_use_PrivateKey_ASN1(EPKEY, ssl_ctx->ssl, privkey_buf, (long)privkey_len);
 
 	if (ret != SSL_SUCCESS) {
 		RTLS_ERR("failed to use private key.\n");
diff --git a/src/tls_wrappers/openssl/x509_openssl10x.c b/src/tls_wrappers/openssl/x509_openssl10x.c
index da269ed..437949d 100644
--- a/src/tls_wrappers/openssl/x509_openssl10x.c
+++ b/src/tls_wrappers/openssl/x509_openssl10x.c
@@ -5,9 +5,8 @@
  */
 
 #include <openssl/opensslv.h>
-
-// clang-format off
 #if OPENSSL_VERSION_NUMBER < 0x10100000L
+// clang-format off
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include <openssl/ssl.h>
diff --git a/src/verifiers/CMakeLists.txt b/src/verifiers/CMakeLists.txt
index 3f0103c..0e4cd6b 100644
--- a/src/verifiers/CMakeLists.txt
+++ b/src/verifiers/CMakeLists.txt
@@ -1,6 +1,8 @@
 add_subdirectory(nullverifier)
 
-include(FindSgxDcapQuoteVerify)
+if(HOST OR TDX OR SGX)
+    include(FindSgxDcapQuoteVerify)
+endif()
 
 if(HOST OR TDX)
     if(SGXDCAPQV_FOUND)
@@ -28,3 +30,7 @@ endif()
 if(SGX)
     add_subdirectory(sgx-la)
 endif()
+
+if(VIRTCCA)
+    add_subdirectory(virtcca)
+endif()
diff --git a/src/verifiers/internal/rtls_enclave_verifier_select.c b/src/verifiers/internal/rtls_enclave_verifier_select.c
index 217bbb7..19303ac 100644
--- a/src/verifiers/internal/rtls_enclave_verifier_select.c
+++ b/src/verifiers/internal/rtls_enclave_verifier_select.c
@@ -32,7 +32,7 @@ rats_tls_err_t rtls_verifier_select(rtls_core_context_t *ctx, const char *name,
 	RTLS_DEBUG("selecting the enclave verifier '%s' ...\n", name);
 
 	enclave_verifier_ctx_t *verifier_ctx = NULL;
-	for (unsigned int i = 0; i < enclave_verifier_nums; ++i) {
+	for (unsigned int i = 0; i < registerd_enclave_verifier_nums; ++i) {
 		RTLS_DEBUG("trying to match %s ...\n", enclave_verifiers_ctx[i]->opts->name);
 
 		if (name && strcmp(name, enclave_verifiers_ctx[i]->opts->name))
diff --git a/src/verifiers/sev-snp/pre_init.c b/src/verifiers/sev-snp/pre_init.c
index 4f9eed4..4525c3f 100644
--- a/src/verifiers/sev-snp/pre_init.c
+++ b/src/verifiers/sev-snp/pre_init.c
@@ -7,28 +7,31 @@
 #include <rats-tls/log.h>
 #include <rats-tls/verifier.h>
 
-#define TOOL_NUM 3
-#define TOOL_BUF 16
+#define TOOL_NUM  3
+#define TOOL_NAME 10
 
 enclave_verifier_err_t sev_snp_verifier_pre_init(void)
 {
 	RTLS_DEBUG("called\n");
 
-	/* These tools are used to verify SEV-SNP report */
-	const char names[TOOL_NUM][TOOL_BUF] = { "openssl", "wget", "csplit" };
-	const char parameters[TOOL_NUM][TOOL_BUF] = { "version", "-V", "--version" };
-
-	for (unsigned int i = 0; i < TOOL_NUM; ++i) {
-		char cmdline_str[64];
+	enclave_verifier_err_t err = ENCLAVE_VERIFIER_ERR_NONE;
 
-		snprintf(cmdline_str, sizeof(cmdline_str), "%s %s >/dev/null 2>&1", names[i],
-			 parameters[i]);
-
-		if (system(cmdline_str)) {
-			RTLS_ERR("Please install %s for sev_snp verifier\n", names[i]);
-			return -ENCLAVE_VERIFIER_ERR_NO_TOOL;
+	/* These tools are used to verify SEV-SNP report */
+	char tools_name[TOOL_NUM][TOOL_NAME] = { "openssl", "wget", "csplit" };
+	char cmdline_str[50] = {
+		0,
+	};
+
+	for (int i = 0; i < TOOL_NUM; i++) {
+		int count = snprintf(cmdline_str, sizeof(cmdline_str),
+				     "which %s 1> /dev/null 2> /dev/null", tools_name[i]);
+		cmdline_str[count] = '\0';
+
+		if (system(cmdline_str) != 0) {
+			RTLS_ERR("please install tool %s\n", tools_name[i]);
+			err = -ENCLAVE_VERIFIER_ERR_NO_TOOL;
 		}
 	}
 
-	return ENCLAVE_VERIFIER_ERR_NONE;
+	return err;
 }
diff --git a/src/verifiers/sev/pre_init.c b/src/verifiers/sev/pre_init.c
index ef89e57..46350e1 100644
--- a/src/verifiers/sev/pre_init.c
+++ b/src/verifiers/sev/pre_init.c
@@ -11,10 +11,13 @@ enclave_verifier_err_t sev_verifier_pre_init(void)
 {
 	RTLS_DEBUG("called\n");
 
-	if (!system("wget -V >/dev/null 2>&1"))
-		return ENCLAVE_VERIFIER_ERR_NONE;
+	enclave_verifier_err_t err = ENCLAVE_VERIFIER_ERR_NONE;
 
-	RTLS_ERR("Please install wget for sev verifier\n");
+	char *cmdline_str = "which wget 1> /dev/null 2> /dev/null";
+	if (system(cmdline_str) != 0) {
+		RTLS_ERR("please install wget for sev(-es) verify\n");
+		err = -ENCLAVE_VERIFIER_ERR_NO_TOOL;
+	}
 
-	return -ENCLAVE_VERIFIER_ERR_NO_TOOL;
+	return err;
 }
diff --git a/src/verifiers/virtcca/CMakeLists.txt b/src/verifiers/virtcca/CMakeLists.txt
new file mode 100644
index 0000000..b87d3d2
--- /dev/null
+++ b/src/verifiers/virtcca/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Project name
+project(verifier_virtcca)
+
+# add_subdirectory(qcbor)
+
+# Set include directory
+set(INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../../include
+                 ${CMAKE_CURRENT_SOURCE_DIR}/../../include/rats-tls
+                 ${CMAKE_CURRENT_SOURCE_DIR}/../../include/internal
+                 ${CMAKE_CURRENT_SOURCE_DIR}
+                 /usr/include
+                 ./qcbor/inc
+                 )
+include_directories(${INCLUDE_DIRS})
+
+# Set dependency library directory
+set(LIBRARY_DIRS ${CMAKE_BINARY_DIR}/src
+                 ${RATS_TLS_INSTALL_LIB_PATH}
+                 )
+
+link_directories(${LIBRARY_DIRS})
+
+# Set source file
+set(SOURCES cleanup.c
+            init.c
+            main.c
+            pre_init.c
+            verify_evidence.c
+            token_parse.c
+            )
+
+# Generate library
+add_library(${PROJECT_NAME} SHARED ${SOURCES})
+target_link_libraries(${PROJECT_NAME} ${RATS_TLS_LDFLAGS} ${RTLS_LIB} qcbor)
+set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${VERSION} SOVERSION ${VERSION_MAJOR})
+
+# Install library
+install(TARGETS ${PROJECT_NAME}
+	DESTINATION ${RATS_TLS_INSTALL_LIBV_PATH})
diff --git a/src/verifiers/virtcca/cleanup.c b/src/verifiers/virtcca/cleanup.c
new file mode 100644
index 0000000..ea0f34f
--- /dev/null
+++ b/src/verifiers/virtcca/cleanup.c
@@ -0,0 +1,20 @@
+/* Copyright (c) 2021 Intel Corporation
+ * Copyright (c) 2020-2021 Alibaba Cloud
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <rats-tls/log.h>
+#include <rats-tls/verifier.h>
+#include "token_parse.h"
+
+enclave_verifier_err_t virtcca_verifier_cleanup(enclave_verifier_ctx_t *ctx)
+{
+	RTLS_DEBUG("called enclave verifier ctx: %p\n", ctx);
+
+	cca_token_t *virtcca_token = (cca_token_t *)ctx->verifier_private;
+
+	free(virtcca_token);
+
+	return ENCLAVE_VERIFIER_ERR_NONE;
+}
diff --git a/src/verifiers/virtcca/init.c b/src/verifiers/virtcca/init.c
new file mode 100644
index 0000000..5e537c4
--- /dev/null
+++ b/src/verifiers/virtcca/init.c
@@ -0,0 +1,23 @@
+/* Copyright (c) 2021 Intel Corporation
+ * Copyright (c) 2020-2021 Alibaba Cloud
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <rats-tls/log.h>
+#include <rats-tls/verifier.h>
+#include "token_parse.h"
+
+enclave_verifier_err_t virtcca_verifier_init(enclave_verifier_ctx_t *ctx, rats_tls_cert_algo_t algo)
+{
+	RTLS_DEBUG("ctx %p, algo %d\n", ctx, algo);
+	cca_token_buf_t *cca_token_buf = calloc(1, sizeof(cca_token_buf_t));
+
+	if (!cca_token_buf) {
+		return -ENCLAVE_ATTESTER_ERR_NO_MEM;
+	}
+
+	ctx->verifier_private = cca_token_buf;
+
+	return ENCLAVE_VERIFIER_ERR_NONE;
+}
diff --git a/src/verifiers/virtcca/main.c b/src/verifiers/virtcca/main.c
new file mode 100644
index 0000000..71d959f
--- /dev/null
+++ b/src/verifiers/virtcca/main.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <rats-tls/verifier.h>
+#include <rats-tls/log.h>
+
+extern enclave_verifier_err_t enclave_verifier_register(enclave_verifier_opts_t *);
+extern enclave_verifier_err_t virtcca_verifier_pre_init(void);
+extern enclave_verifier_err_t virtcca_verifier_init(enclave_verifier_ctx_t *,
+													rats_tls_cert_algo_t algo);
+extern enclave_verifier_err_t virtcca_verify_evidence(enclave_verifier_ctx_t *,
+							   						  attestation_evidence_t *, uint8_t *,
+							   						  uint32_t hash_len,
+							   						  attestation_endorsement_t *endorsements);
+extern enclave_verifier_err_t virtcca_verifier_cleanup(enclave_verifier_ctx_t *);
+
+static enclave_verifier_opts_t virtcca_verifier_opts = {
+	.api_version = ENCLAVE_VERIFIER_API_VERSION_DEFAULT,
+	.flags = ENCLAVE_VERIFIER_OPTS_FLAGS_VIRTCCA,
+	.name = "virtcca",
+	.priority = 10,
+	.pre_init = virtcca_verifier_pre_init,
+	.init = virtcca_verifier_init,
+	.verify_evidence = virtcca_verify_evidence,
+	.cleanup = virtcca_verifier_cleanup,
+};
+
+void __attribute__((constructor)) libverifier_virtcca_init(void)
+{
+	RTLS_DEBUG("called\n");
+
+	enclave_verifier_err_t err = enclave_verifier_register(&virtcca_verifier_opts);
+	if (err != ENCLAVE_VERIFIER_ERR_NONE)
+		RTLS_ERR("failed to register the enclave verifier 'virtcca' %#x\n", err);
+}
diff --git a/src/verifiers/virtcca/pre_init.c b/src/verifiers/virtcca/pre_init.c
new file mode 100644
index 0000000..e176563
--- /dev/null
+++ b/src/verifiers/virtcca/pre_init.c
@@ -0,0 +1,15 @@
+/* Copyright (c) 2021 Intel Corporation
+ * Copyright (c) 2020-2021 Alibaba Cloud
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <rats-tls/log.h>
+#include <rats-tls/verifier.h>
+
+enclave_verifier_err_t virtcca_verifier_pre_init(void)
+{
+	RTLS_DEBUG("called\n");
+
+	return ENCLAVE_VERIFIER_ERR_NONE;
+}
diff --git a/src/verifiers/virtcca/verify_evidence.c b/src/verifiers/virtcca/verify_evidence.c
new file mode 100644
index 0000000..5ed949d
--- /dev/null
+++ b/src/verifiers/virtcca/verify_evidence.c
@@ -0,0 +1,64 @@
+#include <rats-tls/log.h>
+#include <rats-tls/verifier.h>
+#include "token_parse.h"
+
+enclave_verifier_err_t virtcca_verify_evidence(enclave_verifier_ctx_t *ctx,
+						    attestation_evidence_t *evidence, uint8_t *hash, unsigned int hash_len,
+						    __attribute__((unused)) attestation_endorsement_t *endorsements)
+{
+	RTLS_DEBUG("ctx %p, evidence %p, hash %p endorsements %p\n", ctx, evidence, hash,
+		   endorsements);
+
+	int ret;
+	size_t device_cert_len;
+    uint8_t *device_cert_data;
+    cca_token_t virtcca_token = {0};
+
+	cca_token_buf_t *cca_token_buf = (cca_token_buf_t *)ctx->verifier_private;
+	memset(cca_token_buf, 0, sizeof(cca_token_buf_t));
+    memcpy(&cca_token_buf->buf_size, evidence->virtcca.report, sizeof(cca_token_buf->buf_size));
+    if (cca_token_buf->buf_size > (GRANULE_SIZE * MAX_TOKEN_GRANULE_PAGE)) {
+        RTLS_ERR("report data too long\n");
+        return ENCLAVE_VERIFIER_ERR_NO_MEM;
+    }
+
+    memcpy(cca_token_buf->buf, evidence->virtcca.report + sizeof(cca_token_buf->buf_size), cca_token_buf->buf_size);
+
+    memcpy(&device_cert_len, evidence->virtcca.report + sizeof(cca_token_buf->buf_size) + cca_token_buf->buf_size, sizeof(device_cert_len));
+
+    device_cert_data = (uint8_t *)malloc(device_cert_len);
+    if (device_cert_data == NULL) {
+        RTLS_ERR("failed to allocate memory for device_cert_data\n");
+        return ENCLAVE_VERIFIER_ERR_NO_MEM;
+    }
+    memcpy(device_cert_data, evidence->virtcca.report + sizeof(cca_token_buf->buf_size) + cca_token_buf->buf_size + sizeof(device_cert_len), device_cert_len);
+
+    // parse cca_token_buf
+    ret = parse_cca_attestation_token(&virtcca_token, cca_token_buf->buf, cca_token_buf->buf_size);
+    if (ret != VIRTCCA_SUCCESS) {
+        RTLS_ERR("failed to parse virtcca token\n");
+        free(device_cert_data);
+        return ENCLAVE_VERIFIER_ERR_CBOR;
+    }
+	print_cca_attestation_token_raw(&virtcca_token);
+    print_cca_attestation_token(&virtcca_token);
+
+	if (memcmp(virtcca_token.cvm_token.challenge.ptr, hash, hash_len)) {
+		RTLS_ERR("unmatched key binder hash value versus challenge in evidence\n");
+		return ENCLAVE_ATTESTER_ERR_INVALID;
+	}
+
+    // device_cert
+    FILE *device_cert_file = fopen("./aik_cert.der", "wb");
+    if (device_cert_file == NULL) {
+        RTLS_ERR("failed to open file for device certificate\n");
+        free(device_cert_data);
+        return ENCLAVE_ATTESTER_ERR_UNKNOWN;
+    }
+    fwrite(device_cert_data, 1, device_cert_len, device_cert_file);
+    fclose(device_cert_file);
+
+    free(device_cert_data);
+
+	return ENCLAVE_VERIFIER_ERR_NONE;
+}
\ No newline at end of file
-- 
2.37.2.windows.2

