Corda 5 Packaging: Lessons Learned
December 07, 2022
We are going to describe some of the lessons learned in Corda 5 CorDapp packaging since Dev Preview 1 last year. In the year since that release, we’ve tackled some interesting issues and developed solutions that will serve us well into the future. First, let’s do a recap of Corda 5 CorDapp packaging.
Corda 5 CorDapps are Java applications. They are supported by a Gradle plugin that configures Gradle to produce output suitable for Corda. The Gradle project can have dependencies like any other Gradle project, pulling in libraries from Maven Central and other repositories. The JAR file output of the project, which we call Corda Package (CPK), contains special metadata. A single CPK may not be enough to represent an entire application, so the Gradle plugin also supports combining CPKs into one file. That file is called a Corda Package Bundle (CPB) and is intended to represent a complete CorDapp.
Now that we have a CorDapp, we need a network to run it on, so we encapsulate the network joining information inside a Corda Package Installer (CPI). This file contains the CPB and the network joining information. When you want to join a network, you will receive a CPI from the network operator. This file contains the CorDapp and the network joining information. This allows you to upload a single file, be sure that you are running the correct CorDapp, and verify that you are joining the network that you expected.
Corda 5 applies a certain amount of respect to the code signing applied to CPKs. If you were to take CorDapps source code, modify a class that represents state within the CorDapp and then try to use it in place of the original, you’d find that Corda rejects it. The CPK code signer is part of the CPK identity. You can have two CPKs that are identical in all ways except the signature, and they will be treated as distinct. It is not possible to swap out the classes with classes from a different signer, even if they are identical.
This gives the signer a lot of control over the evolution of the classes. There are many situations where that level of control should not rest in the hands of a single person or organization. We need to support multiple signers to distribute control over the future evolution of the classes. We looked at our multi-layered CPK from Dev Preview 1 and realized that it blocked multiple signers. It applied the signature to two layers, one nested inside the other. A second signer would find it impossible to apply a signature without breaking existing signatures, because signing the inner layer would invalidate the outer layer signature of the first signer. To address that, we’ve flattened the CPK structure. Multiple signers can sign the CPK and their signatures will sit side-by-side without invalidating previous signatures.
Stable file hash
When you test a system and report that it passed all tests, it is important to identify what was tested. That could take the form of a version number and name, but the strictest match would be to document the file hash of the system that passed testing. Our initial plan was to create CPIs by adding a single file to the existing CPB. That would have changed the CPB file hash, making it impossible for people to say that the CPI contained the CPB that passed the tests. As a result, we changed the CPI design to embed the CPB unmodified. This allows anyone to extract the CPB from the CPI (using jar or zip commands) and check the file hash. There are still points where the hash will change due to signing, but we’ve minimized file hash changes as much as possible.
Handling expiring certificates
We want you to build on top of Corda. We want your applications to be successful and to be fundamental to the businesses that they support. We want Corda to be a rock-solid foundation for important applications. We have seen how business applications live long lives, often longer than their original authors expected. Now introduce code signing with a certificate that has an expiry date, where the root certificates have 10-year expiry dates and every certificate in the chain has shorter and shorter lifespans. Certificates don’t provide a long-term solution to trust and they never will. So, what do we do? What happens if your CorDapp is the foundation to business that will last 30 years or more?
We are not building an expiry date into CorDapp packaging, and we are not asking you to trust expired certificates. We will check the signature and trust valid signing certificates when a CorDapp is installed. Beyond installation, long-term, we will trust installed CorDapps based on
file hash. This gives us a balance between using signing certificates to establish trust while they are current and continuing to trust what is established as trusted beyond the expiry dates.
Key rotation within CorDapp packaging
We considered how a CorDapp developer might deal with a signing certificate that needs to be replaced. This need may be caused by a compromised key, an expiry, or loss of the private key. Our CPK identity makes the signer important. How does a CorDapp developer replace their signing key? The CPK identity is based on the x500 name component of the signing certificate. As long as the x500 name remains consistent and the Corda cluster operators trust the new certificate, then a replacement certificate with the same x500 name will act as a drop-in replacement for previous certificates. So, the replacement process is to generate a new certificate with the same x500 name and then distribute the certificate to end users to be trusted in their Corda deployments.
In conclusion, we’ve tackled some interesting problems over the last year and have addressed some issues to make our CorDapp packaging a long-term solution for Corda 5.