3. Format et fonctionnement du journal
3. Format et fonctionnement du journal
Quiconque peut soumettre des certificats aux journaux de certificats pour audit public ; toutefois, comme les certificats ne seront pas acceptés par les clients TLS s’ils ne sont pas journalisés, on s’attend à ce que les propriétaires de certificats ou leurs CA les soumettent en général. Un journal est un arbre de Merkle unique, toujours croissant, uniquement append-only, de tels certificats.
Lorsqu’un certificat valide est soumis à un journal, le journal DOIT renvoyer immédiatement un Signed Certificate Timestamp (SCT). Le SCT est l’engagement du journal à incorporer le certificat dans l’arbre de Merkle dans un délai fixe appelé Maximum Merge Delay (MMD). Si le journal a déjà vu le certificat, il PEUT renvoyer le même SCT que précédemment. Les serveurs TLS DOIVENT présenter un SCT provenant d’un ou plusieurs journaux au client TLS avec le certificat. Les clients TLS DOIVENT rejeter les certificats qui n’ont pas de SCT valide pour le certificat de l’entité finale.
Périodiquement, chaque journal ajoute toutes ses nouvelles entrées à l’arbre de Merkle et signe la racine de l’arbre. Les auditeurs peuvent ainsi vérifier que chaque certificat pour lequel un SCT a été émis apparaît bien dans le journal. Le journal DOIT incorporer un certificat dans son arbre de Merkle dans le délai Maximum Merge Delay après l’émission du SCT.
Les opérateurs de journal NE DOIVENT PAS imposer de conditions sur la récupération ou le partage des données du journal.
3.1. Entrées du journal
Quiconque peut soumettre un certificat à n’importe quel journal. Afin de permettre l’attribution de chaque certificat journalisé à son émetteur, le journal DOIT publier une liste de certificats racines acceptables (cette liste peut utilement être l’union des certificats racines approuvés par les principaux fournisseurs de navigateurs). Chaque certificat soumis DOIT être accompagné de tous les certificats supplémentaires requis pour vérifier la chaîne jusqu’à un certificat racine accepté. Le certificat racine lui-même PEUT être omis de la chaîne soumise au serveur de journal.
Alternativement, les autorités de certification (racine ainsi qu’intermédiaires) peuvent soumettre un certificat aux journaux avant émission. Pour ce faire, la CA soumet un Precertificate que le journal peut utiliser pour créer une entrée qui sera valide par rapport au certificat émis. Le Precertificate est construit à partir du certificat à émettre en ajoutant une extension critique spéciale « poison » (OID 1.3.6.1.4.1.11129.2.4.3, dont la extnValue OCTET STRING contient des données ASN.1 NULL (0x05 0x00)) au TBSCertificate de l’entité finale (cette extension vise à garantir que le Precertificate ne peut pas être validé par un client X.509v3 standard) et en signant le TBSCertificate résultant [RFC5280] avec soit
-
un Precertificate Signing Certificate à usage spécial (CA:true, Extended Key Usage: Certificate Transparency, OID 1.3.6.1.4.1.11129.2.4.4). Le Precertificate Signing Certificate DOIT être directement certifié par le certificat de CA (racine ou intermédiaire) qui signera en fin de compte le TBSCertificate de l’entité finale produisant le certificat de l’entité finale (noter que le journal peut assouplir les règles de validation standard pour permettre ceci, tant que le certificat émis sera valide),
-
ou le certificat de CA qui signera le certificat final.
Comme ci-dessus, la soumission du Precertificate DOIT être accompagnée du Precertificate Signing Certificate, s’il est utilisé, et de tous les certificats supplémentaires requis pour vérifier la chaîne jusqu’à un certificat racine accepté. La signature sur le TBSCertificate indique l’intention de l’autorité de certification d’émettre un certificat. Cette intention est considérée comme contraignante (c’est-à-dire qu’une mauvaise émission du Precertificate est considérée comme équivalente à une mauvaise émission du certificat final). Chaque journal vérifie la chaîne de signature du Precertificate et émet un Signed Certificate Timestamp sur le TBSCertificate correspondant.
Les journaux DOIVENT vérifier que le certificat de l’entité finale ou le Precertificate soumis possède une chaîne de signature valide menant à un certificat de CA racine de confiance, en utilisant la chaîne de certificats de CA intermédiaires fournie par le soumetteur. Les journaux PEUVENT accepter des certificats expirés, pas encore valides, révoqués ou autrement non entièrement valides selon les règles de vérification X.509 afin d’accommoder les particularités des logiciels d’émission de certificats des CA. Toutefois, les journaux DOIVENT refuser de publier des certificats sans chaîne valide vers une CA racine connue. Si un certificat est accepté et un SCT émis, le journal acceptant DOIT stocker la chaîne entière utilisée pour la vérification, y compris le certificat ou Precertificate lui-même et y compris le certificat racine utilisé pour vérifier la chaîne (même s’il a été omis de la soumission), et DOIT présenter cette chaîne pour audit sur demande. Cette chaîne est requise pour empêcher une CA d’éviter la responsabilité en journalisant une chaîne partielle ou vide. (Note : cela exclut en pratique les certificats auto-signés et basés sur DANE jusqu’à ce qu’un mécanisme pour contrôler le spam pour ces certificats soit trouvé. Les auteurs accueillent les suggestions.)
Chaque entrée de certificat dans un journal DOIT inclure les composants suivants :
enum { x509_entry(0), precert_entry(1), (65535) } LogEntryType;
struct {
LogEntryType entry_type;
select (entry_type) {
case x509_entry: X509ChainEntry;
case precert_entry: PrecertChainEntry;
} entry;
} LogEntry;
opaque ASN.1Cert<1..2^24-1>;
struct {
ASN.1Cert leaf_certificate;
ASN.1Cert certificate_chain<0..2^24-1>;
} X509ChainEntry;
struct {
ASN.1Cert pre_certificate;
ASN.1Cert precertificate_chain<0..2^24-1>;
} PrecertChainEntry;
Les journaux PEUVENT limiter la longueur de chaîne qu’ils accepteront.
« entry_type » est le type de cette entrée. Des révisions futures de cette version de protocole peuvent ajouter de nouvelles valeurs LogEntryType. La section 4 explique comment les clients doivent traiter les types d’entrée inconnus.
« leaf_certificate » est le certificat de l’entité finale soumis pour audit.
« certificate_chain » est une chaîne de certificats supplémentaires requise pour vérifier le certificat de l’entité finale. Le premier certificat DOIT certifier le certificat de l’entité finale. Chaque certificat suivant DOIT certifier directement celui qui le précède. Le certificat final DOIT être un certificat racine accepté par le journal.
« pre_certificate » est le Precertificate soumis pour audit.
« precertificate_chain » est une chaîne de certificats supplémentaires requise pour vérifier la soumission du Precertificate. Le premier certificat PEUT être un Precertificate Signing Certificate valide et DOIT certifier le Precertificate. Chaque certificat suivant DOIT certifier directement celui qui le précède. Le certificat final DOIT être un certificat racine accepté par le journal.
3.2. Structure de l’horodatage de certificat signé
enum { certificate_timestamp(0), tree_hash(1), (255) }
SignatureType;
enum { v1(0), (255) }
Version;
struct {
opaque key_id[32];
} LogID;
opaque TBSCertificate<1..2^24-1>;
struct {
opaque issuer_key_hash[32];
TBSCertificate tbs_certificate;
} PreCert;
opaque CtExtensions<0..2^16-1>;
« key_id » est le hachage SHA-256 de la clé publique du journal, calculé sur l’encodage DER de la clé représentée comme SubjectPublicKeyInfo.
« issuer_key_hash » est le hachage SHA-256 de la clé publique de l’émetteur du certificat, calculé sur l’encodage DER de la clé représentée comme SubjectPublicKeyInfo. Ceci est nécessaire pour lier l’émetteur au certificat final.
« tbs_certificate » est le TBSCertificate encodé en DER (voir [RFC5280]) du Precertificate — c’est-à-dire, sans la signature et l’extension poison. Si le Precertificate n’est pas signé avec le certificat de CA qui émettra le certificat final, alors le TBSCertificate a également son émetteur modifié pour correspondre à celui de la CA qui émettra le certificat final. Noter qu’il est aussi possible de reconstruire ce TBSCertificate à partir du certificat final en extrayant le TBSCertificate et en supprimant l’extension SCT. Noter également que comme le TBSCertificate contient un AlgorithmIdentifier qui DOIT correspondre à la fois à l’algorithme de signature du Precertificate et à l’algorithme de signature du certificat final, ils DOIVENT être signés avec le même algorithme et les mêmes paramètres. Si le Precertificate est émis en utilisant un Precertificate Signing Certificate et qu’une extension Authority Key Identifier est présente dans le TBSCertificate, l’extension correspondante DOIT également être présente dans le Precertificate Signing Certificate — dans ce cas, le TBSCertificate a également son Authority Key Identifier modifié pour correspondre à l’émetteur final.
struct {
Version sct_version;
LogID id;
uint64 timestamp;
CtExtensions extensions;
digitally-signed struct {
Version sct_version;
SignatureType signature_type = certificate_timestamp;
uint64 timestamp;
LogEntryType entry_type;
select(entry_type) {
case x509_entry: ASN.1Cert;
case precert_entry: PreCert;
} signed_entry;
CtExtensions extensions;
};
} SignedCertificateTimestamp;
L’encodage de l’élément digitally-signed est défini dans [RFC5246].
« sct_version » est la version du protocole à laquelle le SCT se conforme. Cette version est v1.
« timestamp » est l’heure NTP courante [RFC5905], mesurée depuis l’époque (1er janvier 1970, 00:00), en ignorant les secondes intercalaires, en millisecondes.
« entry_type » peut être implicite du contexte dans lequel le SCT est présenté.
« signed_entry » est le « leaf_certificate » (dans le cas d’un X509ChainEntry) ou le PreCert (dans le cas d’un PrecertChainEntry), comme décrit ci-dessus.
« extensions » sont des extensions futures à cette version de protocole (v1). Actuellement, aucune extension n’est spécifiée.
3.3. Inclusion de l’horodatage de certificat signé dans la poignée de main TLS
Les données SCT correspondant au certificat de l’entité finale provenant d’au moins un journal doivent être incluses dans la poignée de main TLS, soit en utilisant une extension de certificat X509v3 comme décrit ci-dessous, soit en utilisant une extension TLS (section 7.4.1.4 de [RFC5246]) de type « signed_certificate_timestamp », soit en utilisant l’agrafe OCSP (Online Certificate Status Protocol) du protocole de statut de certificat en ligne (également connue sous le nom d’extension TLS « Certificate Status Request » ; voir [RFC6066]), où la réponse inclut une extension OCSP avec l’OID 1.3.6.1.4.1.11129.2.4.5 (voir [RFC2560]) et le corps :
SignedCertificateTimestampList ::= OCTET STRING
Au moins un SCT DOIT être inclus. Les opérateurs de serveur PEUVENT inclure plus d’un SCT.
De même, une autorité de certification PEUT soumettre un Precertificate à plus d’un journal, et tous les SCT obtenus peuvent être directement intégrés dans le certificat final, en encodant la structure SignedCertificateTimestampList comme une OCTET STRING ASN.1 et en insérant les données résultantes dans le TBSCertificate comme extension de certificat X509v3 (OID 1.3.6.1.4.1.11129.2.4.2). À la réception du certificat, les clients peuvent reconstruire le TBSCertificate d’origine pour vérifier la signature du SCT.
Le contenu de l’OCTET STRING ASN.1 intégrée dans une extension OCSP ou une extension de certificat X509v3 est le suivant :
opaque SerializedSCT<1..2^16-1>;
struct {
SerializedSCT sct_list <1..2^16-1>;
} SignedCertificateTimestampList;
Ici, « SerializedSCT » est une chaîne d’octets opaque qui contient la structure TLS sérialisée. Cet encodage garantit que les clients TLS peuvent décoder chaque SCT individuellement (c’est-à-dire, s’il y a une montée de version, les clients obsolètes peuvent toujours analyser les anciens SCT tout en sautant les nouveaux SCT dont ils ne comprennent pas les versions).
De même, les SCT peuvent être intégrés dans une extension TLS. Voir ci-dessous pour les détails.
Les clients TLS DOIVENT mettre en œuvre les trois mécanismes. Les serveurs DOIVENT mettre en œuvre au moins l’un des trois mécanismes. Noter que les serveurs TLS existants peuvent en général utiliser le mécanisme d’extension de certificat sans modification.
Les serveurs TLS devraient envoyer des SCT provenant de plusieurs journaux au cas où un ou plusieurs journaux ne seraient pas acceptables pour le client (par exemple, si un journal a été radié pour mauvaise conduite ou a subi un compromis de clé).
3.3.1. Extension TLS
Le SCT peut être envoyé pendant la poignée de main TLS en utilisant une extension TLS de type « signed_certificate_timestamp ».
Les clients qui prennent en charge l’extension DEVRAIENT envoyer une extension ClientHello avec le type approprié et un « extension_data » vide.
Les serveurs DOIVENT envoyer des SCT uniquement aux clients qui ont indiqué la prise en charge de l’extension dans le ClientHello ; dans ce cas, les SCT sont envoyés en définissant « extension_data » à une « SignedCertificateTimestampList ».
La reprise de session utilise les informations de session d’origine : les clients DEVRAIENT inclure le type d’extension dans le ClientHello, mais si la session est reprise, le serveur n’est pas censé le traiter ou inclure l’extension dans le ServerHello.
3.4. Arbre de Merkle
L’algorithme de hachage pour le hachage d’arbre de Merkle est SHA-256.
Structure de l’entrée de l’arbre de Merkle :
enum { timestamped_entry(0), (255) }
MerkleLeafType;
struct {
uint64 timestamp;
LogEntryType entry_type;
select (entry_type) {
case x509_entry: ASN.1Cert;
case precert_entry: PreCert;
} signed_entry;
CtExtensions extensions;
} TimestampedEntry;
struct {
Version version;
MerkleLeafType leaf_type;
select (leaf_type) {
case timestamped_entry: TimestampedEntry;
}
} MerkleTreeLeaf;
Ici, « version » est la version du protocole à laquelle le MerkleTreeLeaf correspond. Cette version est v1.
« leaf_type » est le type de l’entrée de feuille. Actuellement, seul « timestamped_entry » (correspondant à un SCT) est défini. Des révisions futures de cette version de protocole peuvent ajouter de nouveaux types MerkleLeafType. La section 4 explique comment les clients doivent traiter les types de feuille inconnus.
« timestamp » est l’horodatage du SCT correspondant émis pour ce certificat.
« signed_entry » est le « signed_entry » du SCT correspondant.
« extensions » sont les « extensions » du SCT correspondant.
Les feuilles de l’arbre de Merkle sont les hachages de feuille des structures « MerkleTreeLeaf » correspondantes.
3.5. Tête d’arbre signée
Chaque fois qu’un journal ajoute de nouvelles entrées à l’arbre, le journal DEVRAIT signer le hachage d’arbre correspondant et les informations d’arbre (voir le message client Signed Tree Head correspondant à la section 4.3). La signature pour ces données est structurée comme suit :
digitally-signed struct {
Version version;
SignatureType signature_type = tree_hash;
uint64 timestamp;
uint64 tree_size;
opaque sha256_root_hash[32];
} TreeHeadSignature;
« version » est la version du protocole à laquelle le TreeHeadSignature se conforme. Cette version est v1.
« timestamp » est l’heure courante. L’horodatage DOIT être au moins aussi récent que l’horodatage SCT le plus récent dans l’arbre. Chaque horodatage ultérieur DOIT être plus récent que l’horodatage de la mise à jour précédente.
« tree_size » est égal au nombre d’entrées dans le nouvel arbre.
« sha256_root_hash » est la racine de l’arbre de hachage de Merkle.
Chaque journal DOIT produire sur demande une Signed Tree Head (STH) qui n’est pas plus ancienne que le Maximum Merge Delay. Dans le cas improbable où il ne reçoit aucune nouvelle soumission pendant une période MMD, le journal DOIT signer le même hachage d’arbre de Merkle avec un horodatage récent.