No Formal Workgroup | G. Queiroz |
Internet-Draft | September 11, 2018 |
Intended status: Experimental | |
Expires: March 15, 2019 |
JSON Unified Digital Signatures System Standard 1
draft-judsys1-02
A simple digital signature standard designed to be used by regular people and to be of mandatory acceptance and to replace PAdES, XAdES and CAdES.
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."
This Internet-Draft will expire on March 15, 2019.
Copyright (c) 2018 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.
Currently, ITI, the government body responsible of ICP-Brasil, Brazil's PKI (Public Key Infrastructure), endorses three different standards: CAdES, XAdES and PAdES.
Since they are all based on X.509 which is used in SSL, there should be an abundance of good software libraries and end user applications to support at least one of these standard.
This is not the case. While there have been some efforts to write open source libraries and end user applications for ICP-Brasil, they are hard to find and most seem unfinished and abandoned.
ITI provides a digital signature verification web tool, but it is only for CAdES and doesn't seem to work well.
PAdES is a monster of its own kind. In an attempt to replicate the paper experience in the digital world, a PDF file can be signed, edited and resigned by another person in a way that they signed over different version of the same document. This is both hard to implement and hard to explain to end users.
To make matters worse, PDF readers almost never come with the necessary CAs to verify ICP-Brasil digital signatures.
Perhaps as result of this mess of different standards, the ITI admits that, no one is obliged to accept digital signatures in Brazil (see [ITI-FAQ-21]).
This situation is unacceptable. We need a digital signature standard that:
This document aims to provide a digital signature standard that address points one through three. Hopefully, this standard may fulfil the fourth point in the near future.
Any person, group or organization can freely implement this standard so long as the implementation is complete.
The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this document, are to be interpreted as described in [RFC2119].
All apps MUST use the standard translations present in this document when they present in the Language specific rules section.
User: A human being using a JUDSYS app. Unless otherwise specified, users MUST always be considered as non-tech-savvy people.
Signing app: A computer program that digitally signs documents according to this standard.
Verifier app: A computer program that verifies a digital signature according to this standard.
(App) JUDSYS app or implementation: A computer program that is either a singing app or a verifier app or both.
Subject attributes: Certain values that qualify the subject. Ex: email, full name, government issued identification numbers, et cetera.
Natural person: A human begin.
Legal person: A group of people who the Law considers to be its own person.
Software person: A piece of software that acts in the name of a natural or legal person.
Digital signature:
(PKI) Public Key Infrastructure:
(KP) Key Pair:
Certificate: A short signed message that states a key pair is in the control of a specific subject.
(CA) Certificate Authority: A certificate that is allowed to sign other certificates. This is, a CA is an entity (usually a company or government body) that ensures that the subject on a certificate is really the person it names.
(PA) Proof of attribute: A short signed message in which the issuer certifies that a certain attribute is true. Examples: job titles and permissions delegated by the issuer to the subject.
(TA) Time-stamping Authority
This is very similar to the concept of attribute certificates. The names was changed to avoid using the "certificate" in two different contexts that may confuse users.
ICAO: International Civil Aviation Organization.
JSON: JavaScript Object Notation.
All JUDSYS-1 files are JSON encoded with UTF-8.
To avoid canonicalization problems, all signed messages are encoded in base64.
Example:
{"b": 1, "a":2} // becomes { "raw": "eyJiIjogMSwgImEiOjJ9Cg==", // This is to aid humans debugging, not for machines to use "what": "JUDSYS-1 base64" }
All JUDSYS-1 extensions begin with .j1 (dot, jay, one).
For JUDSYS-1 files, all apps MUST use only the file extensions show below:
Extension | Usage |
---|---|
.j1c | Certificates (no private keys) |
.j1a | A single proof of attribute |
.j1k | Certificates with the private keys |
.j1s | Detached digital signature |
.j1e | Encrypted file |
.j1r | Revocation information |
.j1d | Reserved for a future WYSIWYS format |
All apps MUST have proper Unicode support and fonts to display any characters that may be necessary for the country of intended use. This is, an app for France MUST have fonts with accented characters, but MAY have no CJK nor Cyrillic support. An app for Russia MUST have Cyrillic and Latin support, but MAY have no CJK or Mongolian support.
It is RECOMMENDED to store string in NFC (Normal Form Composition).
It is RECOMMENDED that all apps support as much Unicode characters and scripts as possible. It is also RECOMMENDED that all apps include the necessary fonts.
Emoji usage is discouraged.
All dates MUST be encoded as strings according to the [RFC3339].
If the time is not available, it MUST be assumed to be midnight.
Times MUST NOT include fractions of a second.
In this spec, country-like means any sovereign state, international organization or similar. For example, the United Nations, the European Union, the UK and the International Court of Justice are country-like but England and Wales are not.
All countries-like MUST be represented by the upper case three letter codes defined on ISO 3166-1 alpha-3. If a country-like does not have such code, it MUST be full English name with spaces and proper capitalization. Ex: Principality of Sealand not principality of sealand nor PrincipalityOf_Sealand.
International organizations MUST use their upper case English acronym and their full English name separated by a hyphen with spaces on both sides. Ex: ICAO - International Civil Aviation Organization and ICJ - International Court of Justice.
Special cases are:
All JUDSYS-1 certification chains are simple trees with root CAs at the top. Cross-signing or other complicated methods MUST NOT be used.
All JUDSYS-1 files MUST include exactly all the necessary certificates, attribute certificates and revocation files for verifying the file in question.
An exception is made to the root CAs which MUST NOT be included in any JUDSYS-1 file, as they MUST be a part of the apps themselves, preferably in the implementation source code.
A certificate is a signed message in which the issuer certifies that the subject has those keys.
A certificate is an object with the following keys:
All keys are encoded as a dictionaries, which MUST have the following keys:
Each key MUST NOT be used in any algorithms other than the one prescribed on the key usage.
Key material MUST NOT be reused.
Attributes in the singular are a single value and attributes in the plural are arrays.
The CA MUST verify the attributes it will use on certificates it issues. If any verification is not done or fails, the corresponding attributes MUST NOT be included in the issued certificate. Examples:
A CA MAY refuse to issue a certificate if essential properties could not verified. Examples: INT/name, USA/SSN, BRA/RG, BRA/CPF.
A string pointing to an attribute which no other entity shares that value. Examples: BRA/CPF, USA/SSN, INT/passports:number.
This is, two entities are the same when their respective ids (attribute name and value) match. The reverse is not guaranteed.
The syntax is <key> or <key>:<sub-key>. If there is an array, the first value is always used as if it were the only one.
An enum describing the type of the subject. Possible values are: natural person, legal person, and other (ex: software).
Each name is a one line Unicode string.
Each name entry SHOULD be at most 5 KiB long.
All apps MUST support such long names. They MAY, however, show only the beginning of the name by default and have a simple way to show the full name. Example: a tooltip or a button close to the name.
There MUST be at least one name in the INT/names attribute.
Any prefixes, suffixes, infixes, honorifics and similar things attached to the name MUST be verified. Example: a person may never use the prefix "Dr." if they have no valid doctorates degree.
Generic prefixes like "Mr." or "Ms." and job titles MUST NOT be included in any of the names.
For legal persons, it is RECOMMENDED to follow the convention: (<Acronym>) <Full Legal Name> <Any special endings> Examples:
For natural persons, it is RECOMMENDED to follow the convention: (<Nick Name>) <First Name> <Full Middle Name> <Last Name> Examples:
An array of entities. The order MUST NOT be assigned any meaning. The array MAY have any number of elements.
The INT/parents attribute MAY lead to a recursive behaviour. This attribute SHOULD NOT exceed the grandparents generations.
Example:
[ {"id": "BRA/CPF", "INT/names": ["João da Silva"], "BRA/CPF": "123.456.789-00"}, {"id": "BRA/CPF", "INT/names": ["Maria da Silva"], "BRA/CPF": "987.654.321-00"}, {"id": "BRA/CPF", "INT/names": ["Joaquim Freitas"], "BRA/CPF": "987.654.321-00"} ]
Pretty much the same as the INT/parents attribute.
It it is present, the entities INT/parents MUST NOT be considered as legal guardians.
It is absent, the entities INT/parents MAY be assumed to be legal guardians.
Example:
[ {"id": "BRA/CPF", "INT/names": ["João da Silva"], "BRA/CPF": "123.456.789-00"}, {"id": "BRA/CPF", "INT/names": ["Maria da Silva"], "BRA/CPF": "987.654.321-00"}, {"id": "BRA/CPF", "INT/names": ["Joaquim Freitas"], "BRA/CPF": "987.654.321-00"} ]
An array of the subject's email addresses.
The fist entry is considered the main one.
The subject MAY have no email address.
It is RECOMMENDED to have at least one ASCII-only email address.
Examples:
// Okay: [] ["someone@example.com"] ["josé@construções-ltda.br", "jose@construcoes-ltda.br"] ["josé@construções-ltda.br", "jose@xn--construes-ltda-mjb8t.br"] ["josé@construções-ltda.br", "jose@construcoes-ltda.br", "josé@xn--construes-ltda-mjb8t.br"] ["josé@construções-ltda.br"] ["jose@construcoes-ltda.br", "josé@construções-ltda.br"]
For SPAM/robo-calling prevention the subject MUST have the right to refuse the inclusion of the INT/phone attribute.
The phone numbers MUST be encoded as a string array. Each element of that array represents one phone number and MUST include the country and area codes.
The country code part MUST begin with a + (plus sign) and have a space to separate it from the rest of the number. This is mainly to aid humans, by separating the international part from the local one.
The rest of the number SHOULD follow the traditions and conventions of the country in question and MAY include punctuation.
Examples:
// Okay: [] ["+55 (11) 0 0000-0000", "+55 0800 000"] // Wrong: ["+55(11) 0 0000-0000", "+550800000", "55 0800 000"]
Note: This attribute is intended to be used by some legal persons and by pretty much no natural persons.
For security reasons the subject MUST have the right to refuse the inclusion of INT/address attribute.
For privacy reasons the subject SHOULD have the right to refuse the inclusion of INT/pictures attribute. The CA, however, CAN require this attribute but its is encouraged not to require it.
The picture MUST always be static: no animated GIFs or similar.
For natural persons the image MUST be picture of the subject. The specific are left to the CA, but it SHOULD follow the traditions and conventions of the CA's country.
One suggestion for CAs is to follow the ICAO guidelines on photos for passports (see [ICAO-9303]).
For legal persons the image MUST be a logo or other symbol that represents the subject. It MUST NOT be a picture of the owners or of the place where the subject is. Again, specific are left to the CA.
Support for this property in apps is OPTIONAL but RECOMMENDED to those that have a GUI.
Those that decide to implement this property MUST be able do decode both JPEG and PNG.
The picture MUST be data URL encoded using base64 and MUST NOT exceed 1 MiB. The size restriction applies to the image itself, not to the string that encodes it.
The picture MUST NOT be rotated using metadata (see [JPEG-HOFF]) regardless of the file type (JPGE or PNG or other).
Example: (Tux, the Linux mascot)
["data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD//gAiUmVzaXplZCB3aXRoIGV6Z2lmLmNvbSBHSUYgbWFrZXL/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAmACADASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAABgcIAAUE/8QALRAAAQMDAgQFAwUAAAAAAAAAAQIDBAUGEQAHEiExQQgTFCJxFVGBMlJhcrH/xAAXAQEBAQEAAAAAAAAAAAAAAAADAgQF/8QAJhEAAgICAQMCBwAAAAAAAAAAAQIDBAARMQUhQRNxEhQigaHR8P/aAAwDAQACEQMRAD8AsvUleN/cDcWk1yNb1lyajTqbGhtyajLhZStS3XFIbQVjmB7eg6lXPtqtdIDcOnRbm3bqkyNR/rkWkw40GTggoRJKnFlscsFQSWyRk4ynvrNbnavC0ioXI8Dk4kSB3Ck698C/CbuduEncRG2u4Sp77kmnqlRXZ6wt9C0ZJHEOZSUhXI5IKfkarPUYXbHVs34gLGvKsQU06hSWnI3C0StDJdW55xUScgguhZ65GemNWWy4260h1paVtrSFJUk5CgehB+2kgkMsauVKk+DyPfWS6/CxG94Gb4Xi1Ym19auFTwbktx1NQh3XJWOFsAdzxHPwDrw7AWc7ZO2NLpk6U/JqcsmdUHXFlSlyHfevJ6nGQM98Z0P7xRYF8Nrt2tQEKhwZfmtKS4oLDqUlKVgggAjiJAORrsbN3nWLglVS3bho70eo0QoHr22iIs5pYPAtB6JXge5HY9P45dPrtO7akqxH6k58cHR17HnNM1KWGNZGHY5w/F5Y0C7dnKxMkrd9RRmVVGN7iQC2CVDGeWUcQ+caFvANe0y4ttqhbdRkuSXrfkpbjuOElXpnEkoSf6lKwPsMDtpj7+TfUWbLtGLLYaqFdhyGG0KUCrgKCFK4evCOIZP40u/B9ZI22g1KJWJTDlSqzjZU42CEAI4glHPv7lHOBn8aSbrVOCyKsr6c60D53v8AWSlSV4/VUbGNavWIuXKel02ruR3nlqcLb7QdQVHmeYwQPydB7G1941SpuTX7/n2021llLVCXzewf1OFxOOXYBJIz11tbRJ0ajBdWzHGA533G/P4xDbmeEozbHbOKrYOZQLoXetPvWq1+rqbLL/157jy2f2rQnII5YGMdemmzaFqtU2O1KqCm5dQ5KKwD5bZ+yAf9PP41tbSN02rLe+ZdAXAGif7X35yRYlWD0w2hvP/Z"]
Each passport is encoded as a dictionary with the following keys:
Only type, country and number MUST be present.
The given_name and surname are OPTIONAL because some people may have no first or last name. However, at least one of them MUST be included.
Except of dates, it is RECOMMENDED that all fields match the way they are presented on the VIZ (Visual Inspection Zone), rather than the MRZ.
{ "type": "P", "country": "UTO", // This **MAY NOT** match ISO 3166-1, read ICAO Doc 9303 (pages 22 to 29) for details. "number": "L898902C3", "surname": "ERIKSSON", "given_name": "ANNA MARIA", "nationality": "UTOPIAN", "date_of_birth": "1974-08-12", "place_of_birth": "ZENITH", "personal_number": "Z E 184226 B", "sex": "F", /* Do NOT assume it is "F" or "M", other characters, such as "X" may de used. */ "date_of_issue": "2007-04-16", "date_of_expiry": "2012-04-15", "MRZ": "P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<\nL898902C36UTO7408122F1204159ZE184226B<<<<<10" }
👉 Open Question: Should software receive certificates? Ex: Should a bank have a specific certificate only for its web server that is used not for SSL but for singing that it approved clients requests (loans for instance) and singing bank statements?
👉 Open Question: It is feature a good idea?
Nameless certificates are self signed certificates meant for the end user. They are intended to serve as a way for people to start using and testing JUDSYS-1 without the need to pay the CAs.
All nameless certificates MUST have, on both subject and issuer, the INT/name attribute with a single element Nameless Certificate. There MUST NOT be any other names nor any other attributes.
The choice to prohibit names is intentional, as it ensures that no implementation will be able to display an unverified name, thus forcing the user to keep an "address book" to associate each person to their certificate.
A PA, Proof of Attribute, is a short signed message that adds an attribute to the holder under the authority of the issuer.
Any one may issue a proof of attribute. The implementation MUST NOT attempt to verify of the issuer has "public faith" (i.e. what they say is assumed to be true by law). This task MUST be left to the user.
This MUST NOT be an array.
A simple trimmed one line string containing the subject's job title.
The job title MUST NOT include the name of the organization.
All apps MUST show the issuer's name and the job title of the attributes certificate together.
Valid examples:
Wrong examples (organization MUST NOT be in the job title):
All signature attributes MUST NOT be arrays.
The date, reason and implementation attributes are REQUIRED. All others are OPTIONAL, but each country MAY require certain attributes.
Exactly one of the following MUST be present: file and counter-signs.
All implementations MUST counter sign instead of sign in parallel whenever possible.
A dictionary that indicates why the signer is signing this document. Possible keys:
All undefined values MUST be interpreted as false.
Apps MUST NOT add their own keys.
Both the approved and rejected keys MAY be true at the same time. When this happens, it means that the signer approved a part of the document and rejected another. The user MUST be informed when this happens.
A dictionary with the following keys:
The country key MUST be present. All others are MAY be empty.
lat and lon are mainly intended to automatically show markers on maps for the end user.
A string with the time in which the signer claims to have signed the document.
All apps MUST warn the user that this value is just a claim which may be false.
An object containing information about the file being signed.
{ "filename": "contract.txt", "size": 9007199254740991, // in bytes, 8 PiB in this case "had-file": false, // in this case the hash was NOT computed by the app that signed the message "hash": { "algorithm": "SHA-512", "value": "A69F73CCA23A9AC5C8B567DC185A756E97C982164FE25859E0D1DCC1475C80A615B2123AF1F5F94C11E3E9402C3AC558F500199D95B6D3E301758586281DCD26" } }
A signature verification MUST NOT fail because the file was renamed.
An array of base64 string encoding the previous signatures which the signer is countersigning.
A string with the name and the version of the software used to generate the signature. Both the name and the version MUST be included. Ex: goJUDSYS 1.3.14
In the case of application that use software libraries, both MUST be included. Ex: MyApp 0.3.4; goJUDSYS 1.3.4.
Method: POST Content-Type: multipart/form-data
URL: <base url>/issue-cert/<long authorization token>
Form: an unsigned certificate on name unsigned-certificate
Response: a signed certificate.
Method: GET
URL: <base url>/status/<any key id>
Response (main part):
{ "key-id": "<key-id>", "revoked": true, "datetime": "2000-01-01T00:00:00" }
👉
Implementations MUST NOT show any representation of the signatures within the document. Ex: a scanned signature on a corner of a page is forbidden, but showing the signatures in a side panel is allowed.
The implementations MUST NOT encourage the user to print a digital document which already has signatures and add regular signatures to the printed version.
Rather, all paper signatures MUST be done first, then the document SHOULD be scanned by a notary or equivalent and then digital signatures may be added to the resulting file.
All signing apps MUST warn the user when the document they are trying to sign seems to have dynamic content.
All signing apps MUST NOT show the warning to the user if they have checked and failed to find signs of dynamic content on the file being signed.
If a signing app cannot verify the file for dynamic content and it is not on the white list, it MUST warn the user about the possibility of dynamic content.
For PDF, the verification, if implemented, MUST check for, and fail to find all of the following:
For HTML, the verification, if implemented, MUST check for, and fail to find all of the following:
Given the complexity some document formats, all implementations MUST warn the user that the document may contain dynamic content for the following formats:
All signing apps MAY assume that the following file formats have no dynamic content:
All signing apps MUST check extension in a case insensitive manner.
👉 Decide how to handle the case of a user who opened a word file, accidentally added a new line and saved it. The best option seems to be mandatory PAR2 support.
👉 Decide how to handle the case of a user trying to sign a .zip or .rar file. Should they be warned about the fact the signature will only apply to all those files together instead of separately?
The private keys MUST remain within the users control at all times. Cloud implementations MUST NOT have the users key on their servers, not even encrypted.
All apps aimed to support Portuguese MUST support the following Unicode blocks:
English | Portuguese |
---|---|
Certificate | Certificado |
(CA) Certificate Authority | (AC) Autoridade Certificadora |
(PA) Proof of certificate | (CA) Comprovante de Atributo |
(TA) Timestamping Authority | (ACT) Autoridade de Carimbo de Tempo |
(PKI) Public Key Infrastructure | (ICP) Infraestrutura de Chaves Públicas |
Subject | Titular |
Issuer | Emissor |
Hash | Resumo digital (hash) |
All certificates issued for natural persons MUST have the following attributes:
For legal persons, the INT/name attribute MUST be the full "razão social".
Even if official documents show a name in all caps, all names MUST have propper capitalization. Ex: "Pedro de Alântara", not "PEDRO DE ALCÂNTARA" nor "Pedro De Alcântara".
All certificates issued for legal persons MUST have the following attributes:
For legal persons, they SHOULD also have, when possible:
CPF (Cadastro de Pessoas Físicas) number. This MUST be encoded as a trimmed string with the format: 999.999.999/99.
BRA/CPF MUST NOT be encoded as an array.
Example: 001.456.789/00
All apps MUST NOT reject a BRA/CPF entry because the verification digits (the last two) are incorrect.
CNPJ (Cadastro Nacional de Pessoas Jurídicas) number. This MUST be encoded as a trimmed string with the format: 99.999.999/9999-99.
BRA/CNPJ MUST NOT be encoded as an array.
Example: 01.012.123/0001-99
All apps MUST NOT reject a BRA/CNPJ entry because the verification digits (the last two) are incorrect.
RNE (Registro Nacional de Estrangeiros) MUST be encoded as a string with all punctuation.
Example: 👉
Each RG (Registro Geral) MUST be encoded as a dictionaries with the keys:
IF digit IS present THEN short_form = number + "-" + digit + " " + state ELSE short_form = number + " " + state END IF
Example of an RG:
{ // Number with punctuation "number": "12.345.678", // The character after the hyphen when present "digit": "X", // The issuing state (two letter upper case code) "state": "DF", // Issuing organization ("órgão emissor") with diacritics "issuer": "Secretaria de Segurança Pública", // number + " " + state (if digit == "") // number + "-" + digit + " " + state (if digit == "") "short_form": "12.345.678-X DF" }
{ "$id": "https://judsys.github.io/schema/j1c.json", "title": "JUDSYS-1 .j1c file", "type": "object", "required": ["what", "certificates"], "additionalProperties": true, "properties": { "what": { "const": "JUDSYS-1 Certificate File (.j1c)" }, "certificates": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/signed-certificate.json" } } } }
{ "$id": "https://judsys.github.io/schema/j1c.json", "title": "JUDSYS-1 .j1c file", "type": "object", "required": ["what", "certificates"], "additionalProperties": false, "properties": { "what": { "const": "JUDSYS-1 Private Keys File (.j1k)" }, "certificates": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/signed-certificate.json" } }, "private-keys": { "description": "An encrypted message containing an array of private keys for the first certificate present on the certificates array.", "$ref": "https://judsys.github.io/schema/encrypted-object.json" } } }
{ "$id": "https://judsys.github.io/schema/j1s.json", "title": "JUDSYS-1 .j1s file", "type": "object", "required": ["what", "certificates", "signatures"], "additionalProperties": false, "properties": { "what": { "const": "JUDSYS-1 Signature File (.j1s)" }, "certificates": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/signed-certificate.json" }, "description": "This MUST have exactly the necessary certificates to verify the signature file" }, "attributes": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/signed-proof-of-attribute.json" } }, "signatures": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/signed-document-signature.json" } } } }
{ "$id": "https://judsys.github.io/schema/unsigned-document-signature.json", "title": "JUDSYS-1 Unsigned Signature", "type": "object", "required": ["signer-key", "date", "reason", "implementation"], "additionalProperties": true, "properties": { "signer-key": { "type": "string", "description": "The key ID of the signing key of the signer" }, "implementation": { "type": "string", "description": "The names and versions of the application and the software library." }, "date": { "type": "string", "format": "date-time" }, "reason": { "enum": ["as-document", "sent", "created", "approved", "rejected", "delivered", "received", "timestamp", "witness", "matches-original"] }, "location": { "$ref": "https://judsys.github.io/schema/int-address.json" }, "file": { "type": "object", "properties": { "filename": { "type": "string" }, "size": { "type": "number" }, "hash": { "$ref": "https://judsys.github.io/schema/hash.json" }, "had-file": { "type": "boolean", "description": "If true, it means that the signer app had the file and hashed by itself. If false, it means that hash was computed by someone else" } } }, "counter-signs": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/signed-signature.json" } } } }
{ "$id": "https://judsys.github.io/schema/signed-document-signature.json", "title": "JUDSYS-1 Signed Document Signature", "type": "object", "required": ["cert", "raw", "sig"], "additionalProperties": false, "properties": { "what": { "const": "JUDSYS-1 Signed Document Signature" }, "raw": { "type": "string", "description": "A base64 encoding of the document signature." }, "sig": { "type": "string", "description": "A base64 encoding of the signature." } } }
{ "$id": "https://judsys.github.io/schema/hash.json", "title": "JUDSYS-1 salted hash", "type": "object", "required": ["algorithm", "value"], "additionalProperties": true, "properties": { "algorithm": { "enum": ["SHA-3-512"], "description": "The hashing algorithm" }, "value": { "type": "string", "description": "The hash of the salted password, hex encoded" }, "salt": { "type": "string", "description": "The password salt, hex encoded" } } }
Advanced Encryption Standard with 256 bit keys in CBC (Cipher Block Chaining) mode.
{ "$id": "https://judsys.github.io/schema/aes-256-cbc.json", "title": "JUDSYS-1 Algorithm Identifier for AES-256-CBC", "type": "object", "required": ["name", "IV"], "additionalProperties": false, "properties": { "name": { "const": "AES-256-CBC" }, "IV": { "type": "string", "description": "A hex encoding of the initialization vector" } } }
{ "$id": "https://judsys.github.io/schema/encrypted-object.json", "title": "JUDSYS-1 Signed Object", "type": "object", "required": ["what", "raw", "alg", "key_src"], "additionalProperties": false, "properties": { "what": { "const": "JUDSYS-1 Encrypted Object" }, "raw": { "type": "string", "description": "A base64 encoding of the encrypted JSON object." }, "algorithm": { "description": "The encryption algorithm.", "oneOf": [ { "$ref": "https://judsys.github.io/schema/aes-256-cbc.json" } ] }, "key_src": { "enum": ["password", "key-file"] }, "key_id": { "type": "string", "description": "The ID of the public key" }, "key_password": { "type": "object", "properties": { "derivation": { "description": "The key derivation algorithm.", "oneOf": [ { "$ref": "https://judsys.github.io/schema/argon2id.json" } ] }, "hash": { "$ref": "https://judsys.github.io/schema/hash.json" } } } } }
{ "$id": "https://judsys.github.io/schema/signed-object.json", "title": "JUDSYS-1 Signed Object", "type": "object", "required": ["what", "raw", "sig"], "additionalProperties": true, "properties": { "what": { "const": "JUDSYS-1 Signed Object" }, "raw": { "type": "string", "description": "A base64 encoding of the JSON object." }, "sig": { "type": "string", "description": "A base64 encoding of the signature." } } }
{ "$id": "https://judsys.github.io/schema/key.json", "title": "JUDSYS-1 key", "type": "object", "required": ["algorithm", "kind", "id", "usage"], "additionalProperties": true, "properties": { "algorithm": { "type": "string" }, "kind": { "enum": ["public", "private"] }, "id": { "type": "string", "description": "A value that uniquely identifies that key (algorithm dependent)" }, "usage": { "enum": ["identification", "signing", "encryption", "issue-certs", "revoke-certs"] } } }
All RSA private keys MUST have exactly two primes.
The key ID MUST be "RSA/" + sha-3-512(N + "|" + E) (all values are strings and all numbers are in base 10).
{ "$id": "https://judsys.github.io/schema/key-rsa-public.json", "title": "JUDSYS-1 key", "type": "object", "required": ["algorithm", "kind", "id", "N", "E"], "additionalProperties": false, "properties": { "algorithm": { "const": "RSA" }, "kind": { "const": "public" }, "id": { "type": "string", "pattern": "^RSA:[0-9a-fA-F]{128}$" }, "N": { "type": "string", "description": "RSA public modulus N, in base 10" }, "E": { "type": "string", "description": "RSA public exponent E, in base 10" } } }
{ "$id": "https://judsys.github.io/schema/key-rsa-private.json", "title": "JUDSYS-1 key", "type": "object", "required": ["algorithm", "kind", "id", "N", "E", "D", "P", "Q", "DQ", "DP", "QINV"], "additionalProperties": false, "properties": { "algorithm": { "const": "RSA" }, "kind": { "const": "private" }, "id": { "type": "string", "pattern": "^RSA:[0-9a-fA-F]{128}$" }, "N": { "type": "string", "description": "RSA public modulus N, in base 10" }, "E": { "type": "string", "description": "RSA public exponent E, in base 10" }, "D": { "type": "string", "description": "RSA private exponent D, in base 10" }, "P": { "type": "string", "description": "RSA secret prime P, in base 10" }, "Q": { "type": "string", "description": "RSA secret prime Q, in base 10" }, "DP": { "type": "string", "description": "D mod (P-1), in base 10" }, "DQ": { "type": "string", "description": "D mod (Q-1), in base 10" }, "QINV": { "type": "string", "description": "Q^-1 mod P, in base 10" } } }
{ "$id": "https://judsys.github.io/schema/entity.json", "title": "JUDSYS-1 Entity", "type": "object", "required": ["INT/type", "INT/names"], "additionalProperties": true, "properties": { "id": { "type": "string", "description": "The name of the attribute that no other entity will share. Ex: US/SSN, BR/CPF, INT/passport:number" }, "INT/type": { "enum": ["natural person", "legal person", "other"] }, "INT/vulnerable": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true, "description": "A list of entries explaining the reasons why this entity is vulnerable. Ex: iliterate, child, mentally ill, et cetera" }, "INT/names": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true }, "INT/emails": { "type": "array", "items": { "type": "string", "format": "idn-email" }, "minItems": 1, "uniqueItems": true }, "INT/phones": { "type": "array", "items": { "type": "string", "pattern": "^[+][0-9]{1,} .*$" }, "minItems": 1, "uniqueItems": true }, "INT/addresses": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/address.json" }, "minItems": 1, "uniqueItems": true }, "INT/pictures": { "type": "array", "items": { "contentEncoding": "base64", "contentMediaType": "image" }, "minItems": 1, "uniqueItems": true }, "INT/passports": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/passport.json" }, "minItems": 1, "uniqueItems": true }, "INT/parents": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/entity.json" }, "minItems": 1, "uniqueItems": true } } }
{ "$id": "https://judsys.github.io/schema/signed-certificate.json", "title": "JUDSYS-1 Signed Certificate", "type": "object", "required": ["cert", "raw", "sig"], "additionalProperties": false, "properties": { "what": { "const": "JUDSYS-1 Signed Certificate" }, "raw": { "type": "string", "description": "A base64 encoding of the certificate." }, "sig": { "type": "string", "description": "A base64 encoding of the signature." } } }
{ "$id": "https://judsys.github.io/schema/int-address.json", "title": "JUDSYS-1 Address", "type": "object", "required": ["country"], "additionalProperties": false, "properties": { "country": { "type": "string" }, "zip": { "type": "string" }, "comment": { "type": "string", "description": "Text describing addresses that do not fit into the structured model AND/OR additional comments about how to get to the place AND/OR access codes" }, "recipient": { "type": "string" }, "complement": { "type": "string" }, "numberOrBuildingName": { "type": "string" }, "street": { "type": "string" }, "neighbourhood": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string", "description": "If the country does not have states or provinces, this value MUST be a single hyphen '-'" }, "lat": { "type": "number", "minimum": -90, "maximum": 90, "description": "The latitude of the address, preferably of the building entrance" }, "lon": { "type": "number", "minimum": -180, "maximum": 180, "description": "The longitude of the address, preferably of the building entrance" } } }
{ "$id": "https://judsys.github.io/schema/int-passport.json", "title": "JUDSYS-1 Entity", "type": "object", "required": ["country", "number"], "additionalProperties": true, "properties": { "type": { "type": "string", "description": "Type of travel document, usually a 'P' indicating passport." }, "country": { "type": "string", "description": "The country that ISSUED the passport." }, "number": { "type": "string" }, "surname": { "type": "string", "description": "The surname as it appears on the VIZ (Visual Inspection Zone)" }, "givenName": { "type": "string", "description": "The given name as it appears on the VIZ (Visual Inspection Zone)" }, "nationality": { "type": "string" }, "date_of_birth": { "type": "string", "format": "date" }, "place_of_birth": { "type": "string" }, "personal_number": { "type": "string" }, "sex": { "type": "string", "description": "The sex of the passport holder. It may be 'X'." }, "date_of_issue": { "type": "string", "format": "date" }, "date_of_expiry": { "type": "string", "format": "date" }, "MRZ": { "type": "string" } } }
{ "$id": "https://judsys.github.io/schema/unsigned-certificate.json", "title": "JUDSYS-1 Unsigned Certificate", "type": "object", "required": ["subject", "notBefore", "notAfter", "serial", "keys"], "properties": { "serial": { "type": "string" }, "subject": { "$ref": "https://judsys.github.io/schema/entity.json" }, "issuer": { "type": "string", "description": "The key ID of the issue-certs key of the issuer." }, "notBefore": { "type": "string", "format": "date-time" }, "notAfter": { "type": "string", "format": "date-time" }, "keys": { "type": "array", "items": { "$ref": "https://judsys.github.io/schema/key.json" }, "minItems": 1, "uniqueItems": true }, "public-faith": { "type": "array", "items": { "enum": ["timestamp", "matches-original", "delivered"] } } } }
{ "$id": "https://judsys.github.io/schema/signed-certificate.json", "title": "JUDSYS-1 Signed Certificate", "type": "object", "required": ["cert", "raw", "sig"], "additionalProperties": false, "properties": { "what": { "const": "JUDSYS-1 Signed Certificate" }, "raw": { "type": "string", "description": "A base64 encoding of the certificate." }, "sig": { "type": "string", "description": "A base64 encoding of the signature." } } }
[RFC2119] | Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997. |
[RFC3339] | Klyne, G. and C. Newman, "Date and Time on the Internet: Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002. |
[ICAO-9303] | International Civil Aviation Organization, "Machine Readable Travel Documents, Seventh Edition", 2015. |
[ITI-FAQ-21] | ITI - Instituto Nacional de Tecnologia da Informação, "Perguntas Frequentes - Questões Jurídicas - Questão 21", February 2018. |
[JPEG-HOFF] | Hoff, M., "JPEG Orientation: Working with the JPEG/EXIF orientation tag", 2015. |