D3.6/views/implicit_certificate.md

263 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 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 subjects public key and the CAs 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 CAs 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
}
}
```