4.5 KiB
Declarative Schema Validation
In order to make the processing of Zencode more robust, all data used as input and output for its computations is validated according to predefined schemas. This makes the Zencode DSL a declarative language in which data recognition is operated before processing.
The data schemas are added on a per-usecase basis: they refer to specific cryptographic implementations as they are added in Zencode. Careful evaluation regarding their addition is made to realise if old schemas can be extended to include new requirements.
Schemas are expressed in a simple format using Lua scripting syntax, for example:
-- zencode_keypair
keypair = S.record {
schema = S.Optional(S.string),
private = S.Optional(S.hex),
public = S.ecp
}
The schema above is the smallest and most commonly used one, composed by one required field and two optional ones, used to validate the input and output of public/private keypairs to be used in transformations.
The only required field in the schema is the public
key which is validated using the ECP
type (S.
is an abbreviation for the SCHEMA.
namespace). The validation of S.ECP
is an actual cryptographic validation: Zenroom will check that the big integer number represented by the field corresponds to a valid point on the curve. In case the validation is not passed, the execution of the Zencode script will not take place and Zenroom will return a meaningful error message indicating the wrong field.
The other optional field is the private
key which can correspond to any sequence of values, therefore no cryptographic validation is possible for it; in this case then the validation used is one that refers to the encoding of the field: S.hex
is verifying that the value is encoded with a sequence of characters that express only hexadecimal numbers (that is, 0..9 numbers and case-insensitive letters from A to Z). Other encoding tests are also available, for instance S.base64
if that is the encoding used in the specific implementation.
Another more complex example follows:
-- 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
}
In this example no new validations are being used and in fact it just adds fields compared to the previous: it defines a portable packet of ciphertext data that is returned as output of AES-GCM asymmetric encryption as well is accepted as input to AES-GCM decryption. A similarity between these two examples is evident: the presence of the schema
field. This field is a sort of "introspective" indication matching the data structure to its schema specification. If this field is not present (as it is always optional) then no validation on the data structure will take place, meaning the Zencode implementation leaves the risk (and hopefully the validation task) to the host.
This chapter ends with the current implementation of schema validation data types that are currently implemented for symmetric and asymmetric encryption of ciphertexts as well for implicit certificates. The schema implementation for Zencode is maintained into the sourcecode within the source file src/lua/zencode_schemas.lua
and can be accessed by the function ZEN.validate(data,'schema','error')
which is a wrapper of ZEN.assert(validate(data,schemas['schema']),'error')
.
_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
},takes
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
}
}