Les premières millisecondes d'une connexion HTTPS

Les premières millisecondes d'une connexion HTTPS

Rate this post

Convaincu de passer des heures à lire des critiques dithyrambiques, Bob a cliqué avec impatience sur «Passer à la caisse» pour son gallon de lait entier toscan et…

Whoa! Qu'est-ce qui vient juste de se passer?

Au cours des 220 millisecondes écoulées, il s'est passé beaucoup de choses intéressantes qui ont amené Firefox à changer la couleur de la barre d'adresse et à verrouiller le coin inférieur droit. Avec l’aide de Wireshark, mon outil réseau préféré, et une version légèrement modifiée de Firefox, nous pouvons voir exactement Que se passe-t-il.

Avec l'accord de la RFC 2818, Firefox savait que «https» signifiait qu'il devrait se connecter au port 443 sur Amazon.com:

La plupart des gens associent HTTPS à SSL (Secure Sockets Layer) créé par Netscape au milieu des années 90. Cela devient moins vrai avec le temps. Avec la perte de parts de marché de Netscape, la maintenance de SSL a été transférée à l’IETF (Internet Engineering Task Force). La première version post-Netscape a été rebaptisée TLS (Transport Layer Security) 1.0, sortie en janvier 1999. Il est rare de voir un véritable trafic «SSL», car TLS existe depuis 10 ans.

Bonjour client

TLS encapsule tout le trafic dans des «enregistrements» de types différents. Nous voyons que le premier octet sorti de notre navigateur est l'octet hexadécimal 0x16 = 22, ce qui signifie qu'il s'agit d'un enregistrement de type «poignée de main»:

Les deux octets suivants sont 0x0301, ce qui indique qu'il s'agit d'un enregistrement de la version 3.1 qui indique que TLS 1.0 est essentiellement un protocole SSL 3.1.

L’enregistrement de la négociation est divisé en plusieurs messages. Le premier est notre message «Client Hello» (0x01). Il y a quelques choses importantes ici:

  • Au hasard:

    Quatre octets représentent le temps universel coordonné (UTC) actuel dans le format d'époque Unix, soit le nombre de secondes depuis le 1er janvier 1970. Dans ce cas, 0x4a2f07ca. Il est suivi de 28 octets aléatoires. Cela sera utilisé plus tard.
  • ID de session:

    Ici, c’est vide / nul. Si nous nous étions déjà connectés à Amazon.com il y a quelques secondes, nous pourrions éventuellement reprendre une session et éviter une poignée de main complète.
  • Suites chiffrées:

    Voici une liste de tous les algorithmes de chiffrement que le navigateur est disposé à prendre en charge. Son premier choix est un très bon choix de «TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA» suivi de 33 autres personnes qu’il est prêt à accepter. Ne vous inquiétez pas si rien de tout cela n’a de sens. Nous verrons plus tard qu'Amazon ne choisit pas notre premier choix de toute façon.
  • extension nom_serveur:

    C'est un moyen de dire à Amazon.com que notre navigateur tente d'atteindre https://www.amazon.com/. Ceci est très pratique car notre liaison TLS se produit bien avant tout trafic HTTP. HTTP a un en-tête "Host" qui permet aux sociétés d’hébergement Internet à la coupe économique d’empiler des centaines de sites Web sur une seule adresse IP. SSL a traditionnellement requis une adresse IP différente pour chaque site, mais cette extension permet au serveur de répondre avec le certificat approprié recherché par le navigateur. Si rien d'autre, cette extension devrait permettre une semaine supplémentaire d'adresses IPv4.

Bonjour serveur

Amazon.com répond avec un enregistrement de prise de contact qui a une taille énorme de deux paquets (2 551 octets). L'enregistrement a des octets de version de 0x0301, ce qui signifie qu'Amazon a accepté notre demande d'utiliser TLS 1.0. Cet enregistrement contient trois sous-messages avec des données intéressantes:

  1. Message «Server Hello» (2):
    • Nous obtenons la représentation temporelle de l'époque Unix du serveur sur quatre octets et ses 28 octets aléatoires qui seront utilisés ultérieurement.
    • Un identifiant de session de 32 octets au cas où nous souhaiterions nous reconnecter sans grande poignée de main.
    • Sur les 34 suites de chiffrement que nous avons proposées, Amazon a choisi «TLS_RSA_WITH_RC4_128_MD5» (0x0004). Cela signifie qu'il utilisera l'algorithme de clé publique «RSA» pour vérifier les signatures de certificat et les clés d'échange, l'algorithme de chiffrement RC4 pour chiffrer les données et la fonction de hachage MD5 pour vérifier le contenu des messages. Nous en parlerons plus tard. Je pense personnellement que Amazon avait des raisons égoïstes de choisir cette suite de chiffrement. Parmi ceux figurant sur la liste, c'était celui qui nécessitait le moins de ressources processeur, de sorte qu'Amazon puisse surcharger plus de connexions sur chacun de leurs serveurs. Une possibilité beaucoup moins probable est qu'ils voulaient rendre un hommage particulier à Ron Rivest, qui a créé ces trois algorithmes.
  2. Message de certificat (11):
    • Ce message prend 2 464 octets et constitue le certificat que le client peut utiliser pour valider le certificat Amazon. Ce n’est rien d’extraordinaire. Vous pouvez voir la plupart de son contenu dans votre navigateur:
  3. Message «Server Hello Done» (14):
    • Il s’agit d’un message de zéro octet qui indique au client que le processus «Hello» est terminé et que le serveur ne demandera pas de certificat au client.

Vérification du certificat

Le navigateur doit déterminer s'il doit faire confiance à Amazon.com. Dans ce cas, il utilise des certificats. Il examine le certificat d'Amazon et voit que l'heure actuelle se situe entre le "pas avant" du 26 août 2008 et le "pas après" du 27 août 2009. Il vérifie également que la clé publique du certificat est bien autorisé à échanger des clés secrètes.

Pourquoi devrions-nous faire confiance à ce certificat?

Une «signature» est jointe au certificat. Elle est un nombre très long au format big-endian:

N'importe qui aurait pu nous envoyer ces octets. Pourquoi devrions-nous faire confiance à cette signature? Pour répondre à cette question, il est nécessaire de faire un rapide détour dans le monde mathémagique:

Interlude: un court, pas Aussi Effrayant, Guide de RSA

Les gens se demandent parfois si les mathématiques ont un intérêt pour la programmation. Les certificats donnent un exemple très pratique de mathématiques appliquées. Le certificat d'Amazon nous indique que nous devrions utiliser l'algorithme RSA pour vérifier la signature. RSA a été créé dans les années 1970 par les professeurs du MIT, Ron Rivest, Adi Shamir et Len UNEdleman a trouvé un moyen astucieux de combiner des idées de 2000 ans de développement mathématique pour mettre au point un algorithme extrêmement simple:

Vous choisissez deux énormes nombres premiers «p» et «q». Multipliez-les pour obtenir «n = p * q». Ensuite, vous choisissez un petit exposant public «e» qui est «l'exposant de chiffrement» et un inverse spécialement conçu de "E" appelé "d" comme "exposant de décryptage". Vous avez ensuite Rendre public «n» et «e» et garder «d» aussi secret que possible puis jetez «p» et «q» (ou gardez-les aussi secrets que «d»). Il est très important de se rappeler que “e” et “d” sont des inverses l’un de l’autre.

Maintenant, si vous avez un message, il vous suffit d’interpréter ses octets comme un nombre «M». Si vous souhaitez «chiffrer» un message pour créer un «texte chiffré», vous devez calculer:

C ≡ Me (mod n)

Cela signifie que vous multipliez "M" par lui-même "e" fois. Le «mod n» signifie que nous ne prenons que le reste (par exemple, «module») lorsque nous divisons par «n». Par exemple, 11 heures + 3 heures 2 (heures). Le destinataire connaît «d», ce qui lui permet d’inverser le message pour récupérer le message initial:

C ≡ (Me) ≡ Me * d ≡ M1 ≡ M (mod n)

Il est également intéressant de noter que la personne avec “d” peut “signer” un document en affichant un message “M” à l’exposant “d”:

M ≡ S (mod n)

Cela fonctionne parce que «le signataire» rend publics les «S», «M», «e» et «n». Tout le monde peut vérifier la signature «S» avec un simple calcul:

Se ≡ (M)e ≡ Md * e ≡ Me * d ≡ M1 ≡ M (mod n)

Les algorithmes de cryptographie à clé publique tels que RSA sont souvent appelés algorithmes «asymétriques» car la clé de cryptage (dans notre cas, «e») n'est pas égale à (par exemple, «symétrique» avec) la clé de décryptage «d». Réduire tout ce qui est “mod n” rend impossible l’utilisation des techniques simples auxquelles nous sommes habitués, telles que les logarithmes normaux. La magie de RSA fonctionne car vous pouvez calculer / chiffrer C ≡ Me (mod n) très rapidement, mais c’est vraiment dur calculer / déchiffrer C ≡ M (mod n) sans connaître «d». Comme nous l'avons vu précédemment, «d» est dérivé de la factorisation du «n» en fonction de «p» et de «q», ce qui pose un problème difficile.

Vérification des signatures

La chose importante à garder à l’esprit avec RSA dans le monde réel est que tous les chiffres impliqués doivent être gros rendre les choses vraiment difficiles à casser en utilisant les meilleurs algorithmes que nous avons. De quelle taille? Le certificat d'Amazon.com a été «signé» par «l'autorité de certification VeriSign Class 3 Secure Server». Le certificat indique que ce module «n» de VeriSign a une longueur de 2048 bits et comporte cette représentation à 617 chiffres en base 10:

1890572922 9464742433 9498401781 6528521078 8629616064
3051642608 4317020197 7241822595 6075980039 8371048211
4887504542 4200635317 0422636532 2091550579 0341204005
1169453804 7325464426 0479594122 4167270607 6731441028
3698615569 9947933786 3789783838 5829991518 1037601365
0218058341 7944190228 0926880299 3425241541 4300090021
1055372661 2125414429 9349272172 5333752665 6605550620
5558450610 3253786958 8361121949 2417723618 5199653627
5260212221 0847786057 9342235500 9443918198 9038906234
1550747726 8041766919 1500918876 1961879460 3091993360
6376719337 6644159792 1249204891 7079005527 7689341573
9395596650 5484628101 0469658502 1566385762 0175231997
6268718746 7514321

(Bonne chance pour essayer de trouver «p» et «q» dans ce «n» – si vous le pouviez, vous pourriez générer des certificats VeriSign réels.)

Le «e» de VeriSign est égal à 216 + 1 = 65537. Bien entendu, ils gardent leur valeur «d» secrète, probablement sur un périphérique matériel sûr protégé par des scanners rétiniens et des gardes armés. Avant de signer, VeriSign vérifiait la validité du contenu revendiqué par Amazon.com sur son certificat en utilisant une «poignée de main» dans le monde réel qui consistait à consulter plusieurs de leurs documents commerciaux. Une fois que VeriSign était satisfait des documents, ils ont utilisé l'algorithme de hachage SHA-1 pour obtenir une valeur de hachage du certificat contenant toutes les revendications. Dans Wireshark, le certificat complet apparaît comme la partie «signedCertificate»:

C’est un peu un abus de langage car cela signifie en fait que ce sont les octets que le signataire est va signer et pas les octets qui incluent déjà une signature.

La signature "S" est simplement appelée "cryptée" dans Wireshark. Si nous élevons "S" à l'exposant public "e" de VeriSign de 65537 et prenons ensuite le reste, divisé par le module "n", nous obtenons cette valeur hexadécimale de signature "déchiffrée":

0001FFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFF00302130 0906052B0E03021A 05000414C19F8786
871775C60EFE0542 E4C2167C830539DB

Selon la norme PKCS # 1 v1.5, le premier octet est «00» et «garantit que le bloc de cryptage, [when] converti en un entier est inférieur au module. "Le deuxième octet de" 01 "indique qu'il s'agit d'une opération de clé privée (par exemple, une signature). Cette opération est suivie de nombreux octets "FF" utilisés pour compléter le résultat afin de s’assurer qu’il est suffisamment grand. Le remplissage est terminé par un octet «00». Vient ensuite «30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14», qui est la méthode PKCS # 1 v2.1 pour spécifier l’algorithme de hachage SHA-1. Les 20 derniers octets sont un condensé de hachage SHA-1 des octets dans «signedCertificate».

Étant donné que la valeur déchiffrée est correctement formatée et que les derniers octets correspondent à la même valeur de hachage que nous pouvons calculer indépendamment, nous pouvons supposer que quiconque connaissait la clé privée de «CA VeriSign Classe 3 Secure Server» l’a «signée». Nous sommes implicitement convaincus que seul VeriSign connaît la clé privée «d».

Nous pouvons répéter le processus pour vérifier que le certificat «CA de VeriSign Classe 3 Secure Server» a été signé par «l’autorité de certification principale publique de classe 3 publique de VeriSign».

Mais pourquoi devrions-nous faire confiance cette? Il n'y a plus de niveaux dans la chaîne de confiance.

L’autorité de certification principale «VeriSign Class 3 Public Public Certification Authority» supérieure est signée lui-même. Ce certificat a été intégré aux produits Mozilla en tant que bon certificat implicitement approuvé depuis la version 1.4 de certdata.txt dans la bibliothèque NSS (Network Security Services). Il a été enregistré le 6 septembre 2000 par Robert Relyea, de Netscape, avec le commentaire suivant:

“Compilez le framework avec le reste de NSS. Incluez un fichier 'live' certdata.txt avec les certs que nous avons la permission de transmettre à l'open source (des certs supplémentaires seront ajoutés à mesure que nous obtiendrons la permission des propriétaires). ”

Cette décision a eu un impact relativement long puisque la validité du certificat est comprise entre le 28 janvier 1996 et le 1er août 2028.

Comme Ken Thompson l'a si bien expliqué dans ses «Réflexions sur la confiance», il faut en fin de compte faire confiance à quelqu'un. Il n'y a pas moyen de contourner ce problème. Dans ce cas, nous sommes implicitement convaincus que Robert Relyea a fait le bon choix. Nous espérons également que la stratégie de certification intégrée de Mozilla est raisonnable pour les autres certificats intégrés.

Il convient de garder à l’esprit que tous ces certificats et signatures ont simplement été utilisés pour former une chaîne de confiance. Sur Internet, le certificat racine de VeriSign est implicitement approuvé par Firefox bien avant que vous ne vous rendiez sur un site Web. Dans une entreprise, vous pouvez créer votre propre autorité de certification racine que vous pourrez installer sur tout le monde.

Alternativement, vous pouvez éviter de payer des entreprises comme VeriSign et d’éviter les chaînes de confiance des certificats. Les certificats sont utilisés pour établir la confiance en utilisant un tiers de confiance (dans ce cas, VeriSign). Si vous disposez d'un moyen sécurisé de partager une «clé» secrète, telle que chuchoter un long mot de passe dans l'oreille d'une personne, vous pouvez utiliser cette clé pré-partagée (PSK) pour établir la confiance. TLS autorise certaines extensions, telles que TLS-PSK, et mon favori personnel, les extensions TLS avec mot de passe sécurisé (SRP). Malheureusement, ces extensions ne sont pas aussi largement déployées et supportées, elles ne sont donc généralement pas pratiques. De plus, ces alternatives imposent un fardeau: nous devons disposer d’un autre moyen sécurisé de communiquer le secret qui est plus lourd que ce que nous essayons d’établir avec TLS (sinon, pourquoi n’utiliserions-nous pas cette pour tout?).

Une dernière vérification consiste à vérifier que le nom d’hôte figurant sur le certificat correspond à nos attentes. Le commentaire de Nelson Bolyard dans la fonction SSL_AuthCertificate explique pourquoi:

/ * cert est OK. C'est le côté client d'une connexion SSL.
    * Maintenant, vérifiez le champ du nom dans le certificat avec le nom d’hôte désiré.
    * NB: C'est notre seule défense contre les attaques de type Man-In-The-Middle (MITM)! 
    * /

Cette vérification permet d'éviter une attaque de type "homme du milieu", car nous sommes implicitement convaincus que les utilisateurs de la chaîne de sécurité des certificats ne feraient rien de mal, par exemple, signer un certificat prétendant provenir d'Amazon.com, à moins qu'il ne s'agisse d'Amazon. .com. Si un attaquant parvient à modifier votre serveur DNS à l’aide d’une technique telle que l’empoisonnement du cache DNS, vous risquez de penser que vous vous trouvez sur un site de confiance (comme Amazon.com), car la barre d’adresse paraîtra normale. Cette dernière vérification fait implicitement confiance aux autorités de certification pour qu'elles empêchent ces incidents de se produire.

Pre-Master Secret

Nous avons vérifié certaines affirmations concernant Amazon.com et connaissons son exposant de chiffrement public «e» et son module «n». Toute personne écoutant dans le trafic peut également le savoir (comme en témoigne l'utilisation de captures Wireshark). Nous devons maintenant créer une clé secrète aléatoire qu'un espion / attaquant ne peut pas comprendre. Ce n’est pas aussi facile que cela puisse paraître. En 1996, les chercheurs ont découvert que Netscape Navigator 1.1 utilisait seulement trois sources pour créer leur générateur de nombres pseudo-aléatoires (PRNG). Les sources étaient: l'heure du jour, l'identifiant du processus et l'identifiant du processus parent. Comme l’ont montré les chercheurs, ces sources «aléatoires» ne sont pas aussi aléatoires et sont relativement faciles à comprendre.

Comme tout le reste était dérivé de ces trois sources «aléatoires», il était possible de «casser» la «sécurité» SSL en 25 secondes sur une machine datant de 1996. Si vous ne croyez toujours pas qu'il est difficile de trouver le hasard, il suffit de demander aux responsables OpenSSL de Debian. Si vous vous trompez, toute la sécurité qui s’y installe est suspecte.

Sous Windows, les nombres aléatoires utilisés à des fins cryptographiques sont générés en appelant la fonction CryptGenRandom qui hache des bits échantillonnés à partir de plus de 125 sources. Firefox utilise cette fonction avec quelques bits dérivés de sa propre fonction pour créer son générateur de nombres pseudo-aléatoires.

La valeur aléatoire «secret pré-maître» de 48 octets générée n’est pas utilisée directement, mais il est très important de la garder secrète, car de nombreux éléments en découlent. Sans surprise, Firefox rend difficile la recherche de cette valeur. J'ai dû compiler une version de débogage et définir les variables d'environnement SSLDEBUGFILE et SSLTRACE pour la voir.

Dans cette session particulière, le secret pré-maître apparaît dans le fichier SSLDEBUGFILE sous la forme:

4456: SSL[131491792]: Secret pré-maître [Len: 48]
03 01 bb 7b 08 98 a7 49 de e8 e9 b8 91 52 ec 81 ... {... I ..... R ..
4c c2 39 7b f6 ba 1c 0a b1 95 50 29 soit 02 ad e6 L.9 {...... P) ....
ad 6e 11 3f 20 c4 66 f0 64 22 57 7e e 06 6a 3b .n.? .f.d "W ~ ..z;

Notez que ce n’est pas complètement aléatoire. Les deux premiers octets sont, par convention, la version TLS (03 01).

Secrets commerciaux

Nous devons maintenant obtenir cette valeur secrète sur Amazon.com. Selon les souhaits d’Amazon «TLS_RSA_WITH_RC4_128_MD5», nous utiliserons RSA pour ce faire. Vous pourrait Faites en sorte que votre message d'entrée corresponde uniquement au secret pré-maître de 48 octets, mais le RFC de la norme de cryptographie à clé publique (PKCS) n ° 1, version 1.5, nous indique que nous devrions remplir ces octets avec au hasard data pour que l'entrée soit exactement égale à la taille du module (1024 bits / 128 octets). Cela rend plus difficile pour un attaquant de déterminer notre secret pré-maître. Cela nous donne également une dernière chance de nous protéger au cas où nous ferions quelque chose de vraiment stupide, comme de réutiliser le même secret. Si nous réutilisions la clé, l'indexeur verrait probablement une valeur différente placée sur le réseau en raison du remplissage aléatoire.

Encore une fois, Firefox rend difficile de voir ces valeurs aléatoires. J'ai dû insérer des instructions de débogage dans la fonction de remplissage pour voir ce qui se passait:

wrapperHandle = fopen("plaintextpadding.txt", "une")
fprintf(wrapperHandle, "PLAINTEXT =")
pour(je = 0; je < modulusLen; je++)
{
    fprintf(wrapperHandle, "% 02X", bloc[[[[je])
}
fprintf(wrapperHandle, " r  n")
fermer(wrapperHandle)

Dans cette session, la valeur complétée complète était:

00 02 12 A3 EA B1 65 D6 81 6C 13 14 13 62 10 53 23 B3 96 85 FF 24
FA CC 46 11 21 24 A4 81 EA 30 63 95 D4 DC BF 9C CC D0 2E DD 5A A6
41 6A 4E 82 65 7D 70 7D 50 09 17 CD 10 55 97 B9 C1 A1 84 F2 A9 AB
EA 7D F4 CC 54 E4 64 6E 3A E5 91 A0 06 00 03 01 BB 7B 08 98 A7 49
DE E8 E9 B8 91 52 EC 81 4C C2 39 7B F6 BA 1C 0A B1 95 50 29 BE 02
AD E6 AD 6E 11 3F 20 C4 66 F0 64 22 57 7E E1 06 7A 3B

Firefox a pris cette valeur et a calculé «C ≡ Me (mod n) ”pour obtenir la valeur que nous voyons dans l'enregistrement“ Client Key Exchange ”:

Enfin, Firefox a envoyé un dernier message non chiffré, un enregistrement «Change Cipher Spec»:

C’est la façon dont Firefox dit à Amazon qu’elle va commencer à utiliser le secret convenu pour chiffrer son prochain message.

Dériver le maître secret

Si nous avons tout fait correctement, les deux côtés (et seulement ces côtés) connaissent maintenant le secret pré-maître de 48 octets (256 bits). Du point de vue d’Amazon, il existe un léger problème de confiance: le secret pré-maître ne contient que des bits générés par le client, ils ne tiennent aucun compte du serveur ni de ce que nous avons dit précédemment. Nous allons résoudre ce problème en calculant le «secret principal». Selon les spécifications, ceci est effectué en calculant:

maître secret = PRF(pre_master_secret, 
                    "secret maître", 
                    ClientHello.au hasard + ServerHello.au hasard)

"Pre_master_secret" est la valeur secrète que nous avons envoyée précédemment. Le «secret principal» est simplement une chaîne dont les octets ASCII (par exemple, «6d 61 73 74 65 72…») sont utilisés. Nous concaténons ensuite les valeurs aléatoires envoyées dans les messages ClientHello et ServerHello (d'Amazon) que nous avons vus au début.

Le PRF est la «fonction pseudo-aléatoire», également définie dans les spécifications, et très astucieuse. Il combine le secret, l'étiquette ASCII et les données de base que nous lui fournissons à l'aide des versions HMAC (Keyed-Hash Message Authentication Code) des fonctions de hachage MD5 et SHA-1. La moitié de l'entrée est envoyée à chaque fonction de hachage. C’est intelligent parce qu’il résiste assez bien aux attaques, même face aux faiblesses du MD5 et du SHA-1. Ce processus peut générer des retours sur lui-même et itérer à tout jamais pour générer autant d'octets que nécessaire.

Suite à cette procédure, nous obtenons un «secret maître» de 48 octets de

4C AF 20 30 8F 4C AA C5 66 4A 02 90 F2 AC 10 00 39 DB 1D E0 1F CB
E0 E0 9D D7 E6 BE 62 A4 6C 18 06 AD 79 21 DB 82 1D 53 84 DB 35 A7
1F C1 01 19

Générer beaucoup de clés

Maintenant que les deux côtés ont un "secret maître", la spécification nous montre comment nous pouvons obtenir toutes les clés de session nécessaires à l'aide du fichier PRF pour créer un "bloc clé" d'où nous allons extraire des données:

key_block = PRF (SecurityParameters.master_secret,
                "expansion clé",
                SecurityParameters.server_random +
                SecurityParameters.client_random);

Les octets de «key_block» sont utilisés pour renseigner les éléments suivants:

client_write_MAC_secret[SecurityParameters.hash_size]
server_write_MAC_secret[SecurityParameters.hash_size]
clé_écriture_client[SecurityParameters.key_material_length]
clé_écriture_serveur[SecurityParameters.key_material_length]
client_write_IV[SecurityParameters.IV_size]
serveur_écriture_IV[SecurityParameters.IV_size]

Étant donné que nous utilisons un chiffrement de flux au lieu d’un chiffrement de bloc tel que la norme AES (Advanced Encryption Standard), nous n’avons pas besoin des vecteurs d’initialisation (IV). Par conséquent, nous avons simplement besoin de deux clés MAC (Message Authentication Code) de 16 octets (128 bits) pour chaque côté, car la taille du résumé de hachage MD5 spécifiée est de 16 octets. De plus, le chiffrement RC4 utilise une clé de 16 octets (128 bits) dont les deux côtés auront également besoin. Tout compte fait, nous avons besoin de 216 + 216 = 64 octets du bloc de clé.

En exécutant le PRF, nous obtenons ces valeurs:

client_write_MAC_secret = 80 B8 F6 09 51 74 EA DB 29 28 EF 6F 9A B8 81 B0
server_write_MAC_secret = 67 7C 96 7B 70 C5 BC 62 9D 1D 1F 4A A6 79 81 61
client_write_key = 32 13 2C DD 1B 39 36 40 84 4A DE E5 6C 52 46 72
server_write_key = 58 36 C4 0D 8C 7C 74 DA 6D B7 34 0A 91 B6 8F A7

Préparez-vous à être crypté!

Le dernier message de prise de contact envoyé par le client est le «message terminé». Il s’agit d’un message intelligent qui prouve que personne n’a altéré la prise de contact et que nous connaissons la clé. Le client extrait tous les octets de tous les messages de négociation et les place dans un tampon «handshake_messages». Nous calculons ensuite 12 octets de "verify_data" à l'aide de la fonction pseudo-aléatoire (PRF) avec notre clé principale, de l'étiquette "client fini" et d'un hachage MD5 et SHA-1 de "handshake_messages":

verify_data = PRF (master_secret,
                  "client fini",
                  MD5 (handshake_messages) +
                  SHA-1 (handshake_messages)
                 ) [12]

Nous prenons le résultat et ajoutons un octet d’en-tête d’enregistrement «0x14» pour indiquer «terminé» et une longueur d’octets «00 00 0c» pour indiquer que nous envoyons 12 octets de données de vérification. Ensuite, comme tous les futurs messages chiffrés, nous devons nous assurer que le contenu déchiffré n’a pas été falsifié. Puisque notre suite de chiffrement utilisée est TLS_RSA_WITH_RC4_128_MD5, cela signifie que nous utilisons la fonction de hachage MD5.

Certaines personnes deviennent paranoïaques lorsqu'elles entendent le MD5 à cause de certaines faiblesses. Je ne préconise certainement pas de l’utiliser tel quel. Cependant, TLS est intelligent en ce sens qu’il n’utilise pas directement MD5, mais plutôt sa version HMAC. Cela signifie qu'au lieu d'utiliser MD5 (m) directement, nous calculons:

HMAC_MD5 (clé, m) = MD5 ((clé opad) ++ MD5 ((clé ipad) ++ m)

(Le signifie XOR, ++ signifie concaténer, «opad» correspond aux octets «5c 5c… 5c» et «ipad» correspond aux octets «36 36… 36»).

En particulier, nous calculons:

HMAC_MD5 (client_write_MAC_secret,
         seq_num +
         TLSCompressed.type +
         TLSCompressed.version +
         TLSCompressed.length +
         TLSCompressed.fragment));

Comme vous pouvez le constater, nous incluons un numéro de séquence («seq_num») ainsi que les attributs du message en texte clair (ici appelé «TLSCompressed»). Le numéro de séquence déjoue les attaquants qui pourraient essayer de prendre un message précédemment chiffré et de l'insérer en cours de route. Si cela se produisait, les numéros de séquence seraient certainement différents de ceux auxquels nous nous attendions. Cela nous protège également d'un attaquant qui laisse tomber un message.

Il ne reste plus qu'à chiffrer ces octets.

Chiffrement RC4

Notre suite de chiffrement négociée était TLS_RSA_WITH_RC4_128_MD5. Cela nous indique que nous devons utiliser le code 4 de Ron (RC4) pour chiffrer le trafic. Ron Rivest a développé l'algorithme RC4 pour générer des octets aléatoires basés sur une clé de 256 octets. L'algorithme est si simple que vous pouvez le mémoriser en quelques minutes.

RC4 commence par créer un tableau d'octets «S» de 256 octets et le remplit de 0 à 255. Vous parcourez ensuite le tableau en mélangeant des octets à partir de la clé. Vous faites cela pour créer une machine à états qui est utilisée pour générer des octets «aléatoires». Pour générer un octet aléatoire, nous mélangons autour du tableau «S».

Mis graphiquement, cela ressemble à ceci:

Pour chiffrer un octet, nous xorons cet octet pseudo-aléatoire avec l'octet que nous voulons chiffrer. Rappelez-vous que xor’ing un peu avec 1 le fait basculer. Comme nous générons des nombres aléatoires, le xor retournera en moyenne la moitié des bits. Ce basculement aléatoire de bits est effectivement la manière dont nous cryptons les données. Comme vous pouvez le constater, ce n’est pas très compliqué et fonctionne donc rapidement. Je pense que c’est pourquoi Amazon l’a choisi.

Rappelons que nous avons une «clé client_write» et une «clé serveur_écriture». Cela signifie que nous devons créer deux instances RC4: une pour chiffrer ce que notre navigateur envoie et l'autre pour déchiffrer ce que le serveur nous a envoyé.

Les premiers octets aléatoires de l'instance RC4 «client_write» sont «7E 20 7A 4D FE FB 78 A7 33…». Si nous xor ces octets avec l'en-tête non crypté et vérifions les octets de message de «14 00 00 0C 98 F0 AE CB C4 … », Nous obtiendrons ce qui apparaît dans la partie chiffrée que nous pouvons voir dans Wireshark:

Le serveur fait presque la même chose. Il envoie une «spécification de chiffrement modifiée», puis un «message terminé» incluant tous les messages de prise de contact, y compris le message déchiffré version du «message terminé» du client. Par conséquent, cela prouve au client que le serveur a réussi à déchiffrer notre message.

Bienvenue dans la couche d'application!

Maintenant, 220 millisecondes après notre lancement, nous sommes enfin prêts pour la couche application. Nous pouvons maintenant envoyer du trafic HTTP normal qui sera chiffré par la couche TLS avec l’instance d’écriture RC4 et déchiffrer le trafic avec l’instance d’écriture RC4 du serveur. De plus, la couche TLS vérifiera chaque enregistrement en vue de détecter toute falsification en calculant le hachage HMAC_MD5 du contenu.

À ce stade, la poignée de main est terminée. Le type de contenu de notre enregistrement TLS est maintenant 23 (0x17). Le trafic crypté commence par «17 03 01», qui indique le type d’enregistrement et la version de TLS. Ces octets sont suivis de notre taille chiffrée, qui inclut le hachage HMAC.

Cryptage du texte en clair de:

GET /gp/cart/view.html/ref=pd_luc_mri HTTP / 1.1
Hôte: www.amazon.com
Agent utilisateur: Mozilla / 5.0 (Windows; U; Windows NT 6.0; en-US; version: 1.9.0.10) Gecko / 2009060911 Minefield / 3.0.10 (.NET CLR 3.5.30729)
Accepter: text / html, application / xhtml + xml, application / xml; q = 0,9, * / *; q = 0,8
Accepter-Langue: en-us, en; q = 0.5
Accept-Encoding: gzip, deflate
Jeu de caractères accepté: ISO-8859-1, utf-8; q = 0,7, *; q = 0,7
Keep-Alive: 300
Connexion: Keep-Alive
...

va nous donner les octets que nous voyons sur le fil:

Le seul autre fait intéressant est que le numéro de séquence augmente sur chaque enregistrement, il est maintenant 1 (et le prochain enregistrement sera 2, etc.).

Le serveur fait le même type de choses de son côté en utilisant server_write_key. Nous voyons sa réponse, y compris l'en-tête de données de l'application témoin:

Décrypter cela nous donne:

HTTP / 1.1 200 OK
Date: mercredi 10 juin 2009 à 01h09 GMT
Serveur: Serveur
...
Cneonction: fermer
Transfer-Encodage: chunked

Il s’agit d’une réponse HTTP normale qui inclut un en-tête «Server: Server» non descriptif et un en-tête «Cneonction: close» mal orthographié provenant des équilibreurs de charge d’Amazon.

TLS est juste en dessous de la couche d'application. Le logiciel serveur HTTP peut agir comme s’il envoyait du trafic non chiffré. Le seul changement est qu'il écrit dans une bibliothèque qui effectue tout le cryptage. OpenSSL est une bibliothèque open source populaire pour TLS.

La connexion reste ouverte pendant que les deux parties envoient et reçoivent des données cryptées jusqu'à ce que l'une des parties envoie un message «alerte de fermeture», puis ferme la connexion. Si nous nous reconnectons peu de temps après la déconnexion, nous pouvons réutiliser les clés négociées (si le serveur les a toujours mises en cache) sans utiliser d'opérations de clé publique, sinon nous établissons une toute nouvelle poignée de main complète.

Il est important de réaliser que les enregistrements de données d’application peuvent être n'importe quoi. La raison pour laquelle «HTTPS» est spécial est que le Web est si populaire. Il existe de nombreux autres protocoles basés sur TCP / IP qui se basent sur TLS. Par exemple, TLS est utilisé par FTPS et les extensions sécurisées pour SMTP. Il est certainement préférable d’utiliser TLS plutôt que d’inventer sa propre solution. De plus, vous bénéficierez d’un protocole qui a résisté à une analyse de sécurité minutieuse.

… Et nous avons fini!

Le très lisible RFC TLS couvre beaucoup plus de détails qui ont été manqués ici. Nous avons parcouru un seul chemin dans notre observation de la danse de 220 millisecondes entre Firefox et le serveur d’Amazon. Une bonne partie du processus a été affectée par la sélection de la suite de chiffrement TLS_RSA_WITH_RC4_128_MD5 qu'Amazon a faite avec son message ServerHello. C’est un choix raisonnable qui favorise légèrement la vitesse par rapport à la sécurité.

Comme nous l'avons vu, si quelqu'un pouvait secrètement intégrer le «n» module d'Amazon dans ses «p» et «q» respectifs, il pourrait effectivement déchiffrer tout le trafic «sécurisé» jusqu'à ce que Amazon modifie son certificat. Amazon résout ce problème avec un certificat d'une durée d'un an:

L’une des suites de chiffrement proposées était «TLS_DHE_RSA_WITH_AES_256_CBC_SHA», qui utilise l’échange de clé Diffie-Hellman qui possède une belle propriété de «secret de transfert». Cela signifie que si une personne déchiffrait la mathématique de l’échange de clé, elle ne serait pas meilleure. off pour décrypter une autre session. L’un des inconvénients de cet algorithme est qu’il nécessite plus de calculs avec de grands nombres et qu’il est donc un peu plus éprouvant en calcul sur un serveur occupé. L'algorithme «Advanced Encryption Standard» (AES) était présent dans de nombreuses suites proposées. Il diffère du RC4 en ce sens qu’il fonctionne sur des «blocs» de 16 octets à la fois plutôt que sur un seul octet. Comme sa clé peut aller jusqu'à 256 bits, beaucoup le considèrent comme plus sécurisé que le RC4.

En seulement 220 millisecondes, deux points de terminaison sur Internet se sont réunis, ont fourni suffisamment d'informations d'identification pour se faire confiance, ont configuré des algorithmes de cryptage et ont commencé à envoyer du trafic crypté.

Et penser, tout cela pour que Bob puisse acheter du lait.

METTRE À JOUR: J'ai écrit un programme qui suit les étapes de la poignée de main mentionnées dans cet article. Je l'ai posté sur GitHub.


Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *