No Formal Workgroup G. Queiroz
Internet-Draft September 5, 2018
Intended status: Experimental
Expires: March 9, 2019

JSON Unified Digital Signatures System Standard 1
draft-judsys1-01

Abstract

A simple digital signature standard designed to be used by regular people and to be of mandatory acceptance.

Status of This Memo

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 9, 2019.

Copyright Notice

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.


Table of Contents

1. Introduction

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:

  1. Is easy for programmers to implement. Including reference libraries in multiple languages.
  2. Is easy for ordinary people to use on a day to day basis.
  3. Has strict rules to avoid interoperability problems.
  4. Has mandatory acceptance by law.

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.

1.1. Right of Implementation

Any person, group or organization can freely implement this standard so long as the implementation is complete.

1.2. Terminology

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.

2. Encoding

2.1. Files

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"
}

2.1.1. File extensions

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 Attribute certificates
.j1k Certificates with the private keys
.j1s Detached digital signature
.j1e Encrypted file
.j1r Revocation information

2.2. Strings

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.

2.3. Dates

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.

2.4. Country codes

All countries or similar MUST be represented by the upper case two letter codes defined on ISO 3166-1. If a country or similar 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 if it has more than two letters. Ex: ICAO and ICJ. Otherwise the full English name with spaces and capitalization MUST be used. Ex: League of Nations.

Special cases are:

  1. UN for the United Nations (already on the ISO 3166-1).
  2. EU for the European Union (already on the ISO 3166-1).
  3. INT for international things such as passports, names and date of birth.
  4. MERCOSU for the Southern Common Market, Mercosur in Spanish and Mercosul in Portuguese.
  5. UNASU for the Union of South American Nations, UNSAUR in Spanish and UNASUL in Portuguese.
  6. NAFTA for the North American Free Trade Agreement.
  7. HOAX for URSAL - União das Repúblicas Socialistas da America Latina. (just a joke, non-normative)

2.5. Certificate chains

All JUDSYS-1 files MUST include 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 app's source code.

3. Certificates

✏️

3.1. Keys

All keys are encoded as a dictionaries, which MUST have the following keys:

  1. algorithm
  2. id: A hash of the key that uniquely identifies it.
  3. usage: An enum that indicates what the key may be used for. Possible values:
    1. signing: The key is used only to sign digital documents, issue and revoke attribute certificates.
    2. identification: They key is used only to identify the subject. Ex: login.
    3. encryption: The key is used only for any person to encrypt messages to the subject.
    4. certification: The key is used only to issue digital certificates.
    5. revocation: They key is used only to issue certificate revocations.

Each key MUST NOT be used in any algorithms other than the one prescribed on the key usage.

Key material MUST NOT be reused.

3.2. Subject Attributes

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:

  1. If the CA fails to verify that a phone number really belongs to the subject, it MUST never be included.
  2. If the subject of the certificate to be issued forgets to bring their US/SSN, this attribute MUST NOT be included in the certificate.

A CA MAY refuse to issue a certificate if essential properties could not verified. Examples: INT/name, US/SSN, BR/RG, BR/CPF.

3.2.1. INT/type

An enum describing the type of the subject. Possible values are: natural person, legal person, and other (ex: software).

3.2.2. INT/names

Each name is a one line Unicode string.

All name entries each MUST 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/name 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:

  1. (USP) Universidade São Paulo
  2. Monsters Inc.
  3. Empresa Qualquer Serviços e Comércio LTDA

For natural persons, it is RECOMMENDED to follow the convention: (<Nick Name>) <First Name> <Full Middle Name> <Last Name> Examples:

  1. Dennis MacAlister Ritchie
  2. (FHC) Fernando Henrique Cardoso
  3. (Dom Pedro II) Pedro de Alcântara João Carlos Leopoldo Salvador Bibiano Francisco Xavier de Paula Leocádio Miguel Gabriel Rafael Gonzaga

3.2.3. INT/parents

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 1:

[
  {"id": "BR/CPF", "INT/names": ["João da Silva"], "BR/CPF": "123.456.789-00"},
  {"id": "BR/CPF", "INT/names": ["Maria da Silva"], "BR/CPF": "987.654.321-00"},
  {"id": "BR/CPF", "INT/names": ["Joaquim Freitas"], "BR/CPF": "987.654.321-00"}
]

3.2.4. INT/emails

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 RECOMENDED to have at least one ASCII 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"]

3.2.5. INT/phones

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.

3.2.6. INT/addresses

For security reasons the subject MUST have the right to refuse the inclusion of INT/address attribute.

3.2.7. INT/pictures

For privacy reasons the subject SHOULD have the right to refuse the inclusion of INT/picture 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 guidlines 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 RECOMENDED 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"]

3.2.8. INT/passports

Each passport is encoded as a dictionary with the following keys:

  1. type: Indicates the type of document, for passports this is a P.
  2. number: A string, which MAY contain letters, the identifies this passport.
  3. country: The country that issued the passport.
  4. surname: The subject's last name.
  5. given_name: The subject's first name.
  6. nationality: The subject's nationality.
  7. date_of_birth: The subject's date of birth.
  8. place_of_birth: The subject's place of birth.
  9. personal_number: An id number identifying the subject.
  10. sex: The sex or gender of the subject. Note that X and other characters may be used instead of the traditional F and M.
  11. date_of_issue: The date in which the passport was issued.
  12. date_of_expiry: The date in which the passport will expire.
  13. MRZ: the contents on the MRZ (machine readable zone).

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"
}

4. Certification Chain

👉 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?

4.1. Public Key Infrastructure

4.2. Nameless Certificates

👉 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.

The choice to prohibit names is intentional, as it ensures that no app will be able to display an unverified name, thus forcing the user to keep an "address book" to associate each person to their certificate.

4.3. Revocation

5. Proof of attribute

5.1. Standard attributes

5.1.1. INT/job

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:

  1. Consul
  2. Questor
  3. President
  4. CEO
  5. CEO, Cheif Executive Officer
  6. Ministro
  7. Ministro da 1ª turma

Wrong examples (organization MUST NOT be in the job title):

  1. President of the US
  2. Presidente da República
  3. Justice of the Supreme Court
  4. Presidente do Senado
  5. Ministro da 1ª turma do Supremo Tribunal Federal

6. Signatures

6.1. Standard attributes

All signature attributes MUST NOT be arrays.

The INT/date and INT/reason attributes are MANDATORY. All others are OPTIONAL, but each country MAY require certain attributes.

6.1.1. INT/reason

A dictionary that indicates why the signer is signing this document. Possible keys:

  1. sent: The signer sent the document.
  2. created: The signer created the document.
  3. approved: The signer approved or accepted the document (this is the most common type signature).
  4. rejected: The signer rejected the document.
  5. delivered: The signer placed the document where the recipient is expected to look regularly. Example: A server placed an email on the recipient's account.
  6. received: The signer received the document. Example: a person counter-signs with this key to confirm they received an email.
  7. timestamp: The signer testifies that the document existed at that moment in time.
  8. witness: The signer testifies they saw the previous signings occur at the said time and without coercion.
  9. matches-original: The signer testifies that the file being signed is an authentic copy/scan of the original physical document.

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.

6.1.2. INT/location

A dictionary with the following keys:

  1. country: A string with the country code.
  2. zip: A string with the place's ZIP code equivalent according to the the country.
  3. lat: A float in the interval [-90, +90] representing the latitude of the place.
  4. lon: A float in the interval [-180, +180] representing the longitude of the place.
  5. state: A string indicating the state or province of the place, preferably as a code. Examples: "DC" of District of Columbia, USA. "AP" for Amapá, Brazil.
  6. city: The city or municipality of the place.
  7. street: The street name.
  8. number: A string (never a number) with the street number or name of the building.
  9. complement: A string with the complement for the address.
  10. text: A multi line string describing the place according to the rule sin the country. This is mainly intended for countries with different postal conventions.

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.

6.1.3. INT/date

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.

6.1.4. INT/file

An object containing information about the file being signed.

{
    "filename": "contract.txt",
    "size": 9007199254740991, // in bytes, 8 PiB in this case
    "hash": "SHA-3-512=A69F73CCA23A9AC5C8B567DC185A756E97C982164FE25859E0D1DCC1475C80A615B2123AF1F5F94C11E3E9402C3AC558F500199D95B6D3E301758586281DCD26"
}

A signature verification MUST NOT fail because the file was renamed.

6.1.5. INT/counter

An array of base64 string encoding the previous signatures.

A signature verification MUST NOT fail because the file was renamed.

6.2. Signature Request

7. Internet APIs

7.1. Online RESTful

7.1.1. Sign certificate

7.1.2. Certificate revocation status

7.1.3. Timestamp servers

7.2. Browser interaction

8. Smartcards

9. Security and Usability Considerations

✏️

9.1. Mixing digital and paper signatures

9.2. Dynamic Content

All signing apps MUST warn the user when the document they are trying to sign seems to have dynamic content.

All signing apps MUST also 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 MUST check for, and fail to find all of the following:

  1. Any signs of JavaScript.

For HTML, the verification MUST check for, and fail to find all of the following:

  1. The <script> tag.
  2. Properties such as onclick and oninput on any tags.
  3. External URLs for the tags <link> and <style>. Note that links, <a> tag, are fine regardless of the URL they point to and the <script> tag will fail the verification independently of the URL.

For Office Open XML (MOX), Open Document Format for Office Applications (ODF) and older Microsoft Office files, the verification MUST check for, and fail to find all of the following:

  1. OLE content.
  2. (✏️ what else?)

All signing apps CAN assume that the following file formats have no dynamic content:

  1. Image files, including JPEG (.jpg and .jpeg), PNG (.png), GIF (.gif), BMP (.bmp) and TIFF (.tiff and .tif).
  2. Text files, including pure text (.txt) and rich text (.rtf).
  3. Markdown files (.md).
  4. TeX files (.tex).
  5. XML files (.xml).

All signing apps MUST check extension in a case insensitive manner.

9.3. Accidental changes

👉 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.

9.4. Archive files

👉 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?

9.5. User misinterpretation and excessive trust on the machine

9.6. Certificate and password sharing

9.7. Cloud usage

9.8. Side channel attacks

9.9. Document replacement

10. Language Specific Rules

10.1. Portuguese

10.1.1. Unicode Support

All apps aimed to support Portuguese MUST support the following Unicode blocks:

  1. Basic Latin (U+0000..U+007F).
  2. Latin-1 Supplement (U+00A0..U+00FF). This range excludes the need for supporting C1 Controls.

10.1.2. Standard Translations

English Portuguese
(PA) Proof of certificate (CA) Comprovante de Atributo
Certificate Certificado
(CA) Certificate Authority (AC) Autoridade Certificadora
(PKI) Public Key Infrastructure (ICP) Infraestrutura de Chaves Públicas
(TA) Timestamping Authority (ACT) Autoridade de Carimbo de Tempo
Subject Titular
Issuer Emissor

11. Country Specific Rules

11.1. Brazil

All certificates issued for natural persons MUST have the following attributes:

  1. BR/CPF
  2. BR/RG or BR/RNE or INT/passport: The certificate MAY have any combination of them so long as there is at least one.

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:

  1. BR/CNPJ

For legal persons, they SHOULD also have, when possible:

  1. BR/IE (inscrição estadual)
  2. BR/IM (inscrição municipal)
  3. BR/NIRE (junta comercial)

11.2. Subject Attributes

11.2.1. BR/CPF

CPF (Cadastro de Pessoas Físicas) number. This MUST be encoded as a trimmed string with the format: 999.999.999/99.

BR/CPF MUST NOT be encoded as an array.

Example: 001.456.789/00

All apps MUST NOT reject a BR/CPF entry because the verification digits (the last two) are incorrect.

11.2.2. BR/CNPJ

CNPJ (Cadastro Nacional de Pessoas Jurídicas) number. This MUST be encoded as a trimmed string with the format: 99.999.999/9999-99.

BR/CNPJ MUST NOT be encoded as an array.

Example: 01.012.123/0001-99

All apps MUST NOT reject a BR/CNPJ entry because the verification digits (the last two) are incorrect.

11.2.3. BR/RNE

RNE (Registro Nacional de Estrangeiros) MUST be encoded as a string with all punctuation.

Example: ✏️

11.2.4. BR/RG

RG (Registro Geral) MUST be encoded as an array of dictionaries with the keys:

  1. number for the RG number which MUST include punctuation.
  2. digit for the verification digit, i.e. the character after the hyphen. If the subject RG has no digit this string MUST be empty.
  3. state the two letter uppercase code for the federative unit that issued the document.
  4. issuer the institution that actually issued the RG.
  5. short_form a concise string expressing the main things about the RG. The following algorithm MUST be used:

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"
}

11.2.5. BR/Título de Eleitor

11.2.6. BR/NIT

12. JSON Schemas

12.1. Certificate File (.j1c)

{
  "$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-object.json"
      }
    }
  }
}

12.2. Private Keys File (.j1k)

{
  "$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-object.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"
    }
  }
}

12.3. Proof of Attribute File (.j1a)

12.4. Detached Digital Signature File (.j1s)

12.5. Encrypted File (.j1e)

12.6. Revocation Information File (.j1r)

12.7. Hash (optionally salted)

{
  "$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"
    }
  }
}

12.8. AES-256-CBC

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"
    }
  }
}

12.9. Argon2

12.10. ECDSA

12.11. Encrypted Object

{
  "$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"
        }
      }
    }
  }
}

12.12. Signed Object

{
  "$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."
    }
  }
}

12.13. Key

{
  "$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"]
    }
  }
}

12.13.1. RSA

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).

12.13.1.1. RSA Public

{
  "$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"
    }
  }
}

12.13.1.2. RSA Private

{
  "$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"
    }
  }
}

12.13.2. ECDSA Public Key

12.14. Entity (subject of issuer)

{
  "$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
    }
  }
}

12.15. Certificate

{
  "$id": "https://judsys.github.io/schema/certificate.json",
  "title": "JUDSYS-1 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
    },
    "legal-recognition": {
      "type": "array",
      "items": {
        "enum": ["timestamp", "matches-original"]
      }
    }
  }
}

12.16. Address

{
  "$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"
    }
  }
}

12.17. Passport

{
  "$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"
    }
  }
}

13. References

13.1. Normative References

[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.

13.2. Informative References

[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.

Author's Address

Gabriel Villela Noriega de Queiroz Brazil EMail: gabrieljvnq@gmail.com