2725f53ef5
* Initial WIP. * Configure IAS host via system properties. * Create separate Gretty configurations for testing and for IAS. * (WIP) Separate configuration values from WAR; Add msg3 -> msg4 handling. * Check the IAS report's cryptographic signature. * Accept CertPath from IAS instead of a Certificate. * Validate the certificate chain for the IAS report. * Refactor response handling, and add a secret to Message4. * Append public DH keys to generated shared secret. * Use DH secret to generate a 256 bit AES key. * Fix runISV Gradle task so that it creates WAR file. * Migrate MockIAS service into a separate package. * Remove unused aesCMAC field from Message3. * Configure HTTP sessions to expire after 10 idle minutes. * Ensure we select the "isv" key for MTLS with Intel Attestation Service. * Set key alias for Intel's public certificate. * Implement GET /attest/provision endpoint. * Use elliptic curves for Diffie-Hellman keys. * Pass public keys as Little Endian byte arrays without ASN.1 encoding. * Add AES-CMAC signature to Message2. * Remove signature fields from QUOTE body for sending to IAS. * Add a dummy AES-CMAC field to Message3 for later validation. * Generate AEC-CMAC for Message 3, and refactor crypto functionality. * Calculate AES-CMAC using AES/CBC/PKCS5Padding algorithm. * Use BouncyCastle's AESCMAC algorithm for MAC calculation. * Include standard crypto test vectors to the unit tests. * Encrypt MSG3 secret using AES/GCM/NoPadding with 128 bit key. * Hash shared key with Little Endian versions of public keys. * Refactor so that hexToBytes() is a utility. * Simplify signing of MocKIAS report. * Separate AES/GCM authentication tag from the encrypted data. * Create /ias/report endpoint for ISV which proxies IAS. * Remove unnecessary @Throws from MockIAS handlers. * Log HTTP error status from IAS. * Replace runISV task with startISV and stopISV tasks. * Refactor tests to use CryptoProvider @Rule instead of @Suite. * Move Web server for integration tests to use non-production ports. * Add proxy endpoint for IAS revocation list. * Generate an ECDSA "service key" for signing (gb|ga). * Generate a persistent key-pair for the ISV to sign with. * Verify the (Gb|Ga) signature from Message2. * Add debugging aids. * Fix Gradle warning. * Remove TLV header from Platform Info Body for MSG4. * Small tidy-up. * Use SPID "as-is" when calculating CMAC for MSG2. * Add DEBUG messages for MSG2's KDK and SMK values (AES-CMAC). * Add DEBUG logging for ECDH shared secret. * More DEBUG logging. * The ECDH shared secret *is* the x-coordinate: no need to subrange. * Adjust MockIAS to return an empty revocationList for GID 0000000b. * Fix ArrayOutOfBoundsException for "small" integer values. * Test MSG1 with empty revocation list. * Add extra logging for IAS report request. * ReportResponse object cannot be null. * Fix misreading of spec - don't remove quote's signature when requesting report from IAS. * Log invalid contents of X-IAS-Report-Signing-Certificate HTTP header. * Build CertPath for IAS from explicit list of Certificates. * Rename quote fields on IAS ReportResponse to match Intel. * Log report ID and quote status from IAS. * Add a revocation list checker to the certificate path validator. * Tweak revocation list options, depending on IAS vs MockIAS. * Extract Intel's certificate specifically by alias for PKIX. * Tune quote body returned by MockIAS. * Add AES-CMAC field to Message4 for validation. * Increase GCM authentication tag to 128 bits. * Receive platformInfoBlob from IAS as hexadecimal string. * Generate secret encryption key using KDK and SK values. * Marshall platformInfoBlob between Base16 string and ByteArray. * Interpret status results from IAS as enums. * Use lateinit for HttpServletRequest field. * Refactor ExceptionHandler out of messages package. * Alias is for ISV, so rename it. * Refactor classes into more correct packages. * Use random 96 bit IV for GCM encryption. * Parameterise HTTP/HTTPS ports via Gradle. * Do not forward a securityManifest containing only zeros to IAS. * Address review comments. * Review comment: Use NativePRNGNonBlocking for SecureRandom. * Rename isv.pfx to isv-svc.pfx * Rename keystore to isv.pfx, for clarity. * Update scripts so that they no longer require user input. * Generate isv.pfx from the key and certificates. * Remove private key from repository. * Declare an empty PSE Manifest to be invalid. * Generate keystores "on the fly". * Rename integration tests to end in "IT" instead of "Test". * Add README * Turn remote-attestation into a separate Gradle project. |
||
---|---|---|
.. | ||
avian | ||
dependencies | ||
hsm-tool | ||
jvm-enclave | ||
linux-sgx | ||
linux-sgx-driver | ||
noop-enclave | ||
remote-attestation | ||
sign_helper | ||
simple-enclave | ||
tools/jvm-diff | ||
Makefile | ||
README.md | ||
run_in_image.sh | ||
udev-cardreader.rules | ||
with_aesmd.sh | ||
with_hsm_simulator.sh | ||
with_isgx.sh | ||
with_ld_library_path.sh |
The build
Prerequisites
- Install gcc/g++(6), autoconf, automake, ocaml, opendjk(8), libtool, python(2.7)
- Make sure JAVA_HOME points to your OpenJDK 8 installation
- Make sure CXX points to g++ (the project does NOT compile with other compilers like clang!)
- If your hardware supports SGX and you want to use it directly you need to install and load the sgx kernel module (verify by running
lsmod | grep isgx
) and have the sgx service running (on a systemd setup verify by runningsystemctl status aesmd
). Note that this is only required for actually running the binary, the build should work fine without. - The SGX SDK has a simulation mode that doesn't require hardware support. To use this edit
sgx-jvm/jvm-enclave/common/CMakeLists.txt
and changeset(SGX_USE_HARDWARE TRUE)
toFALSE
Toplevel Makefile targets
make
will download all other dependencies and build the sgx_standalone_verify binary, residing atsgx-jvm/jvm-enclave/standalone/build/sgx\_standalone\_verify
, as well as a JNI .so residing atsgx-jvm/jvm-enclave/jni/build/untrusted_corda_sgx.so
make clean
will clean all build targets.make distclean
will clean all build targets and downloaded dependencies. Ordinarily you shouldn't need to run this.
Each project has its own build that may be run individually (check the toplevel Makefile to see how to invoke these)
At this point I suggest running make
before reading further, it takes a while to download all dependencies.
Some reading
Before delving into the code it's strongly recommended to read up on SGX. Some links:
- Short high-level paper on the attestation design: https://software.intel.com/sites/default/files/article/413939/hasp-2013-innovative-technology-for-attestation-and-sealing.pdf
- Medium length description of an example attestation protocol: https://software.intel.com/en-us/articles/intel-software-guard-extensions-remote-attestation-end-to-end-example
- Lengthy programmer's reference including description of SGX specific instructions: https://software.intel.com/sites/default/files/managed/48/88/329298-002.pdf
- Lengthy low-level paper disecting the SGX design, going into hardware details: https://eprint.iacr.org/2016/086.pdf
- Lengthy SDK reference: https://download.01.org/intel-sgx/linux-1.7/docs/Intel_SGX_SDK_Developer_Reference_Linux_1.7_Open_Source.pdf
Corda SGX
The high level goal of the SGX work in Corda is to provide a secure way of verifying transactions. In order to do this we need to be able to run a JVM inside an enclave capable of running contract code. The design decision that contract verification code is without side-effects is imperative here.
The dream is to have a functioning JVM running inside SGX with as few limitations as possible. Clients would then be able to connect to the enclave, the TCB would attest that it is running the JVM image on secure hardware, after which the client can safely submit signed JARs for execution.
Corda would then be able to use this to submit contract code and transactions to run the contract code on.
This is the first iteration of the work, with a lot of limitations. The current JVM is based on Avian which can produce a standalone statically linked binary. The build statically links the enclavelet JAR into the static enclave binary (sgx-jvm/jvm-enclave/build/enclave/cordaenclave.so
) which is then loaded and run by jvm/jvm-enclave/build/sgx\_experiments
.
Breakdown of the build
The current SGX work in Corda is based on 4 semi-distinct projects:
- The Avian JVM (in the
sgx-jvm/avian
subtree. Note this is our own fork) - The SGX linux sdk (in the
sgx-jvm/linux-sgx
subtree. Note this is our own fork) - The JVM enclave code itself, residing in
sgx-jvm/jvm-enclave
. This includes the untrusted and trusted part of the SGXified JVM, mostly C++. - Finally the Corda enclavelet. This is the JAR that will be loaded and run inside the enclave. (built by
./gradlew verify-enclave:jar
Avian
Avian has a code layout perfectly suited for SGX hacking. Each target platform (originally posix
or windows
) needs to implement a fairly straight-forward System
interface providing OS-specific functionality like threading/synchronisation/memory/filesystem primitives. Check sgx-jvm/avian/src/system
for code. We use this to implement an SGX "platform", which is basically a stripped down OS environment. Some additional #ifndef-ing was needed to strip some non-os-specific avian functionality that assumed the existence of a filesystem or networking. This work is maintained in a private fork, it is instructive to read through the diff, see https://bitbucket.org/R3-CEV/avian-sgx/.
SGX SDK
There are some modifications in the upstream SGX SDK that we require to run the JVM. An example would be the ability to make the heap executable for JIT compilation, or exposing hooks into malloc to detect OOM conditions. All of these should be mergeable, but we maintain a fork to speed up development on our side.
Corda Enclavelet
This is the JAR that will be run inside the enclave. Check verify-enclave/src/../Enclavelet.kt
for the code.
Currently the JAR is not loaded at runtime, but is rather embedded statically into the enclave itself using Avian's binaryToObject utility. This basically does an objcopy and lets the linker do the embedding later. This will later be changed to dynamic loading of signed JARs.
The JVM enclave
This consists of two parts: the untrusted code that loads the enclave and provides the OCALLs (see sgx-jvm/jvm-enclave/main.cpp
), and the trusted enclave that constructs the JVM using JNI and runs the enclavelet class. (see sgx-jvm/jvm-enclave/enclave/enclave.cpp
).
Dynamic loading, linkage
Avian by default loads some JVM specific code dynamically, and looks up these symbols at runtime. We link these symbols statically and provide a simple binary search lookup at runtime to find the symbols corresponding to symbol name strings. To see how this is done check sgx-jvm/jvm-enclave/enclave/gen_dispatch_table.py
.
Avian also statically links against system libraries providing usual OS functionality. We deal with this by stubbing all of the undefined symbols and implementing/mocking them as needed. The stub generation simply greps for undefined symbols when running make, check sgx-jvm/jvm-enclave/enclave/gen-stubsyms.sh
for this. The implemented/mocked OS functions reside in sgx-jvm/jvm-enclave/enclave/os_support.cpp