## Implicit Certificates This section will illustrate a Zencode implementation of the Elliptic Curve Qu-Vanstone implicit certificate scheme (ECQV) as described by the Standards for Efficient Cryptography 4 (SEC4, 2014). > The ECQV implicit certificate scheme is intended as a general purpose certificate scheme for applications within computer and communications systems. It is particularly well suited for application environments where resources such as bandwidth, computing power and storage are limited. ECQV provides a more efficient alternative to traditional certificates. The ECQV is identifiable as a simple yet important building block within DECODE, as it permits the efficient creation of certificates that contain only the public reconstruction data instead of the subject’s public key and the CA’s signature, also resulting into a smaller payload than traditional certificates. ECQV relates well to those DECODE pilots in need to authenticate participants according to signed credentials, where the issuance of a public key is subject to the verification of certain conditions by a Certificate Authority (CA) capable of verifying and signing those conditions. This scenarios applies well to the pilot experimentations ongoing in Amsterdam for the DECODE project, where a certificate (and a keypair) is issued based on attributes that are certified by the municipal register and then used for authentication procedures operated by third parties and based on those attributes. The limit of this implementation is the lack of threshold certification, a problem that will be solved by the Coconut [cit] implementation in Zencode language, which is still a work in progress. However it should be noted that only one pilot in DECODE (Amsterdam's Gebiedonline) may benefit from this feature, which is however not vital to the deployment. ### Differences with traditional certificates To justify the implementation and adoption of ECQV in place of traditional certificates, here are quickly listed three salient characteristics, closely referring to the documentation offered by the SEC4-1.0 document. With traditional certificates, when an entity U requests a traditional certificate for a public key, U should prove to the CA it knows the corresponding private key. This is to prevent U from choosing an arbitrary public key, that may already belong to another user, and have it certified. This situation is clearly undesirable (and may even lead to security problems). With implicit certificates this proof is unnecessary, as there is no public key before the certificate is issued. Further, U has no control over the final value of his public key, due to the CA’s contribution, making it impossible for U to cause the confusion described above. Unlike traditional certificates, an implicit certificate does not contain a digital signature. In fact, one could simply choose an arbitrary identity I and a random value to form a certificate. Together with the public key of a CA, this generates a public key for the entity identified by I. However, if one constructs an implicit certificate in such a way, i.e., without interacting with the CA, it is infeasible to compute the private key that corresponds to the public key generated by the certificate. Another difference between traditional certificates and implicit certificates is that when presented with a valid traditional certificate, one knows that the certificate belongs to someone. A valid certificate containing the certificate data string IU is a proof that the CA signed this certificate for U , and also that U knows the private key corresponding to the public key included in the certificate. One does not have this guarantee with implicit certificates, satisfying certain privacy conditions made evident by the GDPR. ### Zencode Implementation This section will demonstrate the Zencode implementation in four steps, covering all the transformations into a human-readable language from the mathematical formula to the implementation capable of being executed in the Zenroom VM without any external dependency. The first step is the mathematical formula for ECQV as explained in the SEC4 document. ![Mathematical formulation of the ECQV implicit certificate scheme](ecqv.png) The second step is the implementation of this formula into the machine language executed by the Zenroom VM (a dialect of LUA). ``` -- Zenroom 0.8.0 -- setup random = RNG.new() order = ECP.order() G = ECP.generator() -- make a request for certification ku = INT.new(random, order) Ru = G * ku -- keypair for CA dCA = INT.new(random, order) -- private QCA = G * dCA -- public (known to Alice) -- from here the CA has received the request k = INT.new(random, order) kG = G * k -- public key reconstruction data Pu = Ru + kG declaration = { public = Pu:octet(), requester = str("Alice"), statement = str("I am stuck in Wonderland.") } declhash = sha256(OCTET.serialize(declaration)) hash = INT.new(declhash, order) -- private key reconstruction data r = (hash * k + dCA) % order -- verified by the requester, receiving r,Certu du = (r + hash * ku) % order Qu = Pu * hash + QCA assert(Qu == G * du) ``` The third step is the improvement of the previous implementation using meaningful variable and function names. ``` -- Zenroom 0.8.1 -- setup random = RNG.new() order = ECP.order() G = ECP.generator() -- typical EC key generation on G1 function keygen(rng,modulo) local key = INT.new(rng,modulo) return { private = key, public = key * G } end -- generate the certification request certreq = keygen(random,order) -- certreq.private is preserved in a safe place -- certreq.public is sent to the CA along with a declaration declaration = { requester = str("Alice"), statement = str("I am stuck in Wonderland") } -- Requester sends to CA --> -- ... once upon a time ... -- --> CA receives from Requester -- keypair for CA (known to everyone as the Mad Hatter) CA = keygen(random,order) -- from here the CA has received the request certkey = keygen(random,order) -- certkey.private is sent to requester -- certkey.public is broadcasted -- public key reconstruction data certpub = certreq.public + certkey.public -- the certification is serialized (could use ASN-1 or X509) certification = { public = certpub, requester = declaration.requester, statement = declaration.statement, certifier = str("Mad Hatter") } CERT = sha256(OCTET.serialize(certification)) CERThash = INT.new(CERT, order) -- private key reconstruction data certpriv = (CERThash * certkey.private + CA.private) % order -- CA sends to Requester certpriv and CERThash -- eventually CA broadcasts certpub and CERThash -- ... on the other side of the mirror ... -- Alice has received from the CA the certpriv and CERT -- which can be used to create a new CERTprivate key CERTprivate = (certpriv + CERThash * certreq.private) % order -- Anyone may receive the certpub and CERThash and, knowing the CA -- public key, can recover the same CERTpublic key from them CERTpublic = certpub * CERThash + CA.public -- As a proof here we generate the public key in a standard way, -- multiplying it by the curve generator point, then check equality assert(CERTpublic == G * CERTprivate) print "Certified keypair:" I.print({ private = CERTprivate:octet():base64(), public = CERTpublic:octet():base64() }) ``` At last, the implementation in Zencode follows, clearly showing the simplification made possible by Zenroom for the ECQV implicit certificate cryptographic scheme. Each of the following "scenarios" are blocks of code that can be executed independently from one another, taking validated input and output data structures. ``` -- Zenroom 0.9 Scenario 'keygen': $scenario Given that I am known as 'MadHatter' When I create my new keypair Then print my keyring Scenario 'request': Make my declaration and request certificate Given that I introduce myself as 'Alice' and I have the 'public' key 'MadHatter' in keyring When I declare to 'MadHatter' that I am 'lost in Wonderland' and I issue my implicit certificate request 'declaration' Then print all data Scenario 'keygen': $scenario Given that I am known as 'Alice' and I have a 'declaration_public' 'from' 'Alice' Then print data 'declaration_public' Scenario 'keygen': $scenario Given that I am known as 'Alice' and I have a 'declaration_keypair' Then print data 'declaration_keypair' Scenario 'issue': Receive a declaration request and issue a certificate Given that I am known as 'MadHatter' and I have a 'declaration_public' 'from' 'Alice' and I have my 'private' key in keyring When I issue an implicit certificate for 'declaration_public' Then print all data Scenario 'split': Print the public section of the certificate Given I have a 'certificate_public' 'from' 'MadHatter' When possible Then print data 'certificate_public' Scenario 'split': Print the private section of the certificate Given I have a 'certificate_private' When possible Then print data 'certificate_private' Scenario 'save': Receive a certificate of a declaration and save it Given I have a 'certificate_private' 'from' 'MadHatter' and I have the 'private' key 'declaration_keypair' in keyring When I verify the implicit certificate 'certificate_private' Then I print data 'declaration' Scenario 'keygen': $scenario Given that I am known as 'Bob' When I create my new keypair Then print my keyring Scenario 'challenge': Receive a certificate of a declaration and use it to encrypt a message Given that I am known as 'Bob' and I have my 'private' key in keyring and that 'Alice' declares to be 'lost in Wonderland' and I have a 'certificate' 'from' 'MadHatter' When I draft the text 'Hey Alice! can you read me?' and I use 'certificate' key to encrypt the text into 'ciphertext' Then I print data 'ciphertext' Scenario 'respond': Alice receives an encrypted message, decrypts it and sends an encrypted answer back to sender Given that I am known as 'Alice' and I have my 'private' key in keyring When I decrypt the 'ciphertext' to 'decoded' and I use 'certificate' key to encrypt 'decoded' into 'answer' Then I print data 'answer' ``` The Zencode language is a DSL enforcing a strong declarative behavior underneath and all base data structures are checked against a validation scheme upon input and output. The checks are also of cryptographic nature, for instance public keys are checked to make sure they are actual points on the elliptic curve in use. Here below the data validation schemes so far in use: ``` _G['schemas'] = { -- packets encoded with AES GCM AES-GCM = S.record { checksum = S.hex, iv = S.hex, schema = S.Optional(S.string), text = S.hex, zenroom = S.Optional(S.string), encoding = S.string, curve = S.string, pubkey = S.ecp }, -- zencode_keypair keypair = S.record { schema = S.Optional(S.string), private = S.Optional(S.hex), public = S.ecp }, -- zencode_ecqv certificate = S.record { schema = S.Optional(S.string), private = S.Optional(S.big), public = S.ecp, hash = S.big, from = S.string, authkey = S.ecp }, certificate_hash = S.Record { schema = S.Optional(S.string), public = S.ecp, requester = S.string, statement = S.string, certifier = S.string }, declaration = S.record { schema = S.Optional(S.string), from = S.string, to = S.string, statement = S.string, public = S.ecp }, declaration_keypair = S.record { schema = S.Optional(S.string), requester = S.string, statement = S.string, public = S.ecp, private = S.hex } } ```