Introducing Smart Contracts to BlockCerts
We have the pleasure to share the result of a university student project at the department for Information Systems Engineering (ISE) at TU Berlin, aiming to improve the Blockcerts framework by making use of the Ethereum blockchain’s capabilities. The project was initiated by a cooperation between Deutsche Gesellschaft für Internationale Zusammenarbeit (GIZ) GmbH and SEAMEO Innotech.
The value added of this extension lies in, on the one hand, the shift of core functionalities (e.g. issuance and revocation of certificates) to smart contracts located on the Ethereum blockchain, and, on the other hand, the utilization of the Ethereum Name System (ENS) enabling a secure and highly available way of authenticating issuer identities.
With this post, we present our forks of cert-issuer and cert-verifier, as well as our newly developed cert-deployer of which the latter one can be used to deploy smart contracts managing the issuing and revocation process. Backwards compatibility is ensured for all components at any time.
This post is structured as follows: We start by giving a brief overview of the project’s goals, continue with the illustration of our conceptual approach and lastly present specific details of the implementation.
In our initial considerations, we identified some weak points in the design of the current BlockCerts implementation. The central problem we see is the way external data is stored and queried from web servers. Each issuing institution has to host both a file proving its identity and a list of revoked certificates on a server. This approach is prone to availability and security issues. This is particularly true for smaller institutions – as it is not trivial to run an updated and secure web server. Even a temporary outage would lead to valid certificates being indistinguishable from invalid ones. Outages, especially longer ones, could thus render existing certificates useless.
Tackling this non-optimum way of managing the issuer’s identity and the list of revoked certificates, we identified the following requirements that need to be met:
- Maximum availability
- Consistent and continuous chain of trust
- Cost efficiency
The basis of the changes we propose is the introduction of a smart contract to store a certificate’s proof of existence on the blockchain over using transaction payloads. To address the aforementioned issues, vulnerable functionality is transferred to the blockchain.
Both issuing and revoking can be done via the smart contract on the Ethereum blockchain. Since the Bitcoin blockchain does not provide the required capabilities, it will not be supported. Additionally, we introduce the ENS to link human-readable names to smart contracts. As a consequence, the issuer’s identity can be strongly asserted which requires the issuer to publicly advertise this name.
As stated before, the current Blockcerts implementation relies on revocation lists hosted on local servers to be retrieved for the verification process. This design has some weak points we have addressed.
The value of using the blockchain lies in the availability, consistency and immutability guarantees it offers. The current implementation of BlockCerts undermines this by storing data critical to the verification process on web servers. As João Santos and Kim Hamilton Duffy put it previously: “This [design] has known limitations, including: centralization, single point of failure”.
A system is only as strong as its weakest link.
For this reason we decided to move the vulnerable components to the blockchain, in order for the system as a whole to maintain the blockchain’s guarantees. This includes changing the way both the issuer’s identity and the list of revoked certificates are handled.
We propose to handle revocations in a smart contract. Each certificate and batch has an explicit state associated with it. This way revocations can be achieved by changing their state in the smart contract. Additionally, querying this state can be done in one call to the blockchain.
To verify an issuer’s identity, the corresponding hosted issuer.json file has to be validated. This file is generally accessible via a URL on the certificate. The only information to be cross-referenced by humans: the domain name itself, which, for any given institution, is public knowledge. Thus, a strong chain of trust can be established. We aim to move this chain of trust to the blockchain.
Using ENS addressable blockchain resources, such as smart contracts, can be linked to a human-readable name, e.g. tu-berlin.eth. When an institution’s Blockcerts smart contract is deployed, its ENS domain is instructed to point to their smart contract. In any certificates issued to this contract, this ENS name will be present the same way the issuer’s URL was previously. If institutions advertise their domain and it becomes public knowledge, this chain of trust established supersedes the former one, as ENS comes with the same availability guarantees as the blockchain itself.
Smart contracts, in our implementation, have the role of server-like mediators we have chosen over the current Blockcerts approach using transaction payloads to write data to the blockchain, due to its flexibility, while maintaining availability and security guarantees a blockchain provides. Generally, the contract bundles functionalities for both issuing and revoking certificates. This is achieved by mapping hashes to certain states while hashes can explicitly be either a batches’ merkle root hash or the one of a single certificate. In our current design, there are three states: not_issued, valid and revoked. Remarkably, the use of a mapping ensures a constant complexity for issuing certificates, thus minimizing gas-costs. Since no gas-costs are incurred by calling data from the ethereum blockchain, the verification process does not consume any gas at all.
To authenticate issuers, incoming transactions are only allowed, if they are sent by the originally deploying account. Internally, this is ensured by an only_owner modifier within the smart contract.
After registering an ENS domain, an organization can establish a human readable link between a smart contract and the related entity. Additionally, the deploying organization could register some subdomains with respectively deployed smart contracts being controlled by different accounts (faculties, departments, etc.) to form a hierarchical system.
The contract is shipped in source with the deployer package and only compiled upon deployment onto the blockchain. This is beneficial for two reasons: First, the code can be reviewed, ensuring it contains no malevolent functions. Second, if an institution wishes to make changes to the inner workings of the contract, this can be easily done.
The cert-deployer package provides the tools for deploying Blockcerts smart contracts to the Ethereum blockchain and preparing them to receive and revoke issued certificates. On a basic level three things happen one after another: Initially, the contract is locally compiled from source, deployed onto the blockchain, and the institution’s ENS domain linked to the contract afterwards.
Though being a completely new feature within the Blockcerts environment, syntactic and stylistic compatibility in every way has always been of highest priority throughout the entire implementation process. Nevertheless, crucial differences, as using the web3 framework and infura nodes for interacting with the Ethereum blockchain and relating services, are part of our optimization approach that can be found in our cert-issuer and cert-verifier modifications, too.
As indicated earlier, there are two administrative requirements potential issuers have to meet before they can start deploying smart contracts. First, they have to set up an Ethereum wallet and, second, register an ENS domain. Both the ropsten test network as well as the Ethereum mainnet chains are supported. In a scenario, where an ENS domain already points to an existing smart contract, the configuration contains a flag (overwrite_ens_link) that has to be explicitly set to enable overwriting this link. This is especially meant to prevent accidental data loss or unnecessary expenses.
Finally, configuration parameters, as it has always been, can be found in a configuration file. Most of the cert-deployer’s configuration is similar to the one of the cert-issuer presented more in more detail below.
Setup and dependencies
All dependencies required can be installed by running:
python setup.py install
The issuer was subject to two main changes: First, another Ethereum blockchain handler was added with an accessible wrapper that enables interaction with smart contract functions. On this basis, the ability to issue and revoke certificates was set up and some configuration options were added for these features.
The main contribution to the issuer can be found in the addition of an ethereum_sc blockchain handler. Being a wrapper for the web3 library this module enables the issuer to interact with smart contracts in general and, via the interface model defined in
ServiceProviderConnector, implements the same interface as the other blockchain handlers. Thus, only minor adjustments were required to enable issuing of certificate hashes to the smart contract.
The main changes made to the existing program logic were needed to embed the necessary information about how to verify within the certificates. This information includes a valid contract address and contract abi. More information on this can be found in the cert-schema section. The required information is generated in
Lastly, the ability to revoke certificates was implemented. In the current implementation certificate IDs are used to identify certificates in the revocation list. For a reduced footprint on the blockchain, we opted to identify certificates by their hash. When running with the
--revoke flag, a json file containing a list of hashes to be revoked is referenced. One by one, the hashes are processed. In case of failure, the hashes that have not been revoked at that point are written back into the file. A list of certificate hashes that have already been revoked is kept locally.
The following options were added:
issuing_method = <transaction(default)|smart_contract>
This indicates whether to use the smart contract backend or the current transaction-based approach. As explained below, due to dependency clashes this distinction also has to be made at install time.
node_url = <ethereum web3 (public) node url (e.g. infura)>
The web3py library requires an ethereum node that is compatible with the json-rpc interface. The easiest option is to use a public node e.g. infura’s, or connect to a locally-run node such as geth or parity.
ens_name = <Your ENS name registered with your ethereum address that points to your smart contract>
The ENS domain that points to a smart contract deployed with cert-deployer.
contract_address = <smart_contract_address>
This argument is not required. The contract address can be queried from the provided ENS entry.
revocation_list_file = <path-to-your-revocation_list>
This file lists certificates that will be revoked when passing the --revoke flag when running from the command line.
Setup and dependencies
The smart contract backend requires the web3 module to interact with the blockchain. This dependency is incompatible with the ethereum module required by the current implementation. For this reason, there is an install-time option to install the smart contract backend.
python setup.py install experimental --blockchain=ethereum_smart_contract
Backwards compatibility is preserved insofar as that the current implementation can be installed in a separate virtual environment. To switch, there is only one flag to be adapted in the config file. We further switched to the chainpoint3 library, a fork of the chainpoint library, as there was another dependency conflict.
The verifier has been extended to support the usage of issuer smart contracts while ensuring backwards compatibility. Using ENS entries, the package can now verify if a given smart contract belongs to a certain issuer. An ABI, an ENS entry and a smart contract address are now embedded in the anchor field of signed certificates. In addition to the new verification process, we tried to make the console outputs more user friendly.
Following checks are done to verify a certificate, which is issued with the new method:
- Tamper Check - same as before
- Expiration Check - same as before
- Revocation / Validity Check
- ENS Check
We adjusted the tamper check to support our implementation. This way, the verifier is able to check if a certificate has been tampered or not. The important certificate fields are hashed and compared to the provided target hash. The merkle proof is calculated the same as before and will cause the validation to fail if the target hash does not belong to the merkle root hash.
For the expiration check there were no changes made. We implemented the same step as before for our smart contract-based certificates.
Revocation / Validity check
The issuer owned smart contract provides a function, which returns three different states of an hash.
These states are not issued, revoked and valid. To verify if a certificate is valid, the following checks are done:
- If merkle root hash and target hash differ from each other, the merkle root hash should be issued and not revoked, while the target hash should not be revoked.
- If merkle root hash and target hash are equal, then the merkle root hash should be issued and not revoked.
Since ENS is our trust anchor, we have added a new verification step. This verification step compares the address in the ENS Name with the smart contract address embedded in the anchors
contract_address field and checks if they match. If there is an attempt to change the ENS Name in the certificate, the verifier will mark the validation as failed.
We have added a config.ini file to enable later changes of the ens registry or the blockchain access point. We believe this config file is a good addition for individual use cases, although it should stay the same in most of the cases.
We have extended the current v2 schema implementation by adding some extra relevant fields into
anchors field, that are meant to map the correlation between the certificate being issued and corresponding smart contract and an ENS name owner.
Our current design requires ENS name owners to have their ENS domains registered and the corresponding smart contract deployed on the blockchain. Both of them are used in the verification process described above, specifically in the validity- and ENS check.
anchors field looks as follows:
Contains an ENS name of a certificate issuer.
Transaction id in which the smart contract was called.
Contains the smart contract’s address that this certificate was issued to. This value is compared to the address the ENS name points to.
Is used by the verifier to identify the method to use in the verification process. Example:
["type" : "ETHSmartContract"]
Which chain the certificate was issued to. As smart contracts are not supported by the Bitcoin blockchain, only the Ethereum chains are supported.
The application binary interface (ABI) is necessary to communicate with the smart contract.
sourceId are present in the chainpoint v2 schema used.
The additional fields used are therefore non-standard extensions. Ideally, a way is found to incorporate the functionality into the standard or a way is found to offer the same functionality while adhering to the standard.