Thunderbird, RNP et l'importance d'une bonne API





J'ai récemment discuté avec un développeur  Thunderbird  de la conception d'API. Au cours de cette conversation, j'ai partagé mes réflexions sur RNP , une  nouvelle implémentation d'OpenPGP que Thunderbird a récemment commencé à utiliser à la place de GnuPG .



L'interlocuteur était sceptique quant à ma thèse selon laquelle l'API RNP a besoin d'être améliorée et a demandé: "N'est-ce pas subjectif - quelle API est meilleure et laquelle est pire?" Je reconnais que nous n'avons pas de bonnes métriques pour évaluer les API. Mais je ne suis pas d'accord sur le fait que nous ne sommes en principe pas en mesure de juger l'API.



En fait, je soupçonne que la plupart des programmeurs expérimentés reconnaîtront une mauvaise API s'ils la voient. Je pense que plus loin dans cet article, il s'avérera de développer une bonne heuristique, que je vais essayer de construire sur ma propre expérience avec (et plus) GnuPG,  Sequoiaet RNP. Ensuite, je vais passer en revue l'API RNP. Malheureusement, non seulement cette API peut être facilement utilisée à mauvais escient, mais elle est également trompeuse, elle ne devrait donc pas encore être utilisée dans des contextes critiques pour la sécurité. Mais le public cible de Thunderbird est constitué de personnes connues pour être vulnérables, telles que les journalistes, les militants, les avocats et leurs partenaires de communication; tous ces gens ont besoin de protection. À mon avis, cela signifie que Thunderbird devrait réfléchir une fois de plus à l'opportunité d'utiliser RNP.



Remarque: je suggère également de lire cet e-mail:  Utilisons les bibliothèques GPL dans Thunderbird! que j'ai soumis  au poste Thunderbird Development Planning .



Quels sont les traits d'une mauvaise API?



Avant de commencer Sequoia avec Justus et Kai  , nous travaillions tous les trois sur GnuPG . Nous avons non seulement fouillé dans gpg nous-mêmes, mais nous avons également parlé et collaboré avec de nombreux utilisateurs de gpg ultérieurs. Les gens ont pu dire  beaucoup de bonnes choses sur GnuPG .





En ce qui concerne la critique de gpg, les plus significatives étaient deux types de critiques à propos de l'API. Le premier se résume à ceci: L'API gpg est trop dogmatique. Par exemple, gpg utilise une approche de trousseau de clés. Par conséquent, vous ne pouvez afficher ou utiliser un certificat OpenPGP que s'il a été importé dans la base de clés personnelle. Mais certains développeurs veulent d'abord examiner le certificat, puis seulement l'importer. Par exemple, lorsque vous recherchez un certificat sur un serveur de clés par son empreinte digitale, vous pouvez vérifier et vous assurer que le certificat renvoyé est vraiment celui dont vous avez besoin.car son URL s'auto-authentifie. Cela peut être fait en utilisant gpg, mais uniquement de manière contournée, en contournant les principes du modèle de programmation qui y est intégré. L'idée de base est la suivante: créez un répertoire temporaire, ajoutez-y un fichier de configuration, dites à gpg d'utiliser un autre répertoire, importez le certificat là-bas, vérifiez le certificat, puis effacez le répertoire temporaire. Ceci est une recommandation officielle ajoutée par  Justus  sur la base de nos conversations avec les utilisateurs gpg suivants. Oui, cette méthode fonctionne. Mais cela nécessite d'écrire du code spécifique au système d'exploitation, ce code est lent et des bogues y sont souvent introduits.



Une autre classe de remarques que nous avons rencontrées à plusieurs reprises est que pour travailler avec gpg, vous devez connaître beaucoup de choses non évidentes - afin de ne pas abuser de ce mécanisme. Ou, pour le dire autrement, vous devez être très prudent lorsque vous utilisez l'API gpg pour éviter d'introduire par inadvertance une vulnérabilité dans votre code.



Pour mieux comprendre la deuxième préoccupation, considérez les vulnérabilités EFAIL... Le principal problème avec l'API de décryptage gpg: lors du décryptage d'un message, gpg donnera du texte brut, même si l'entrée a été corrompue. gpg renvoie une erreur dans ce cas, mais certains programmes produisent toujours du texte brut sous une forme corrompue. Alors pourquoi pas? Il vaut certainement mieux montrer au moins une partie du message que de ne rien montrer, non? Eh bien, les vulnérabilités EFAIL montrent comment un attaquant peut en profiter pour injecter un bogue Web  dans un message chiffré. Lorsqu'un utilisateur consulte ce message, un bogue Web s'échappe du message. Phew.



Alors, à qui est la faute de ce bug? Les développeurs de GnuPG  ont  insisté sur le fait que le problème se situe au niveau de l'application, dans la mesure où ils n'utilisent pas correctement gpg:



il est recommandé aux agents utilisateurs de messagerie de respecter le code d'état DECRYPTION_FAILED et de ne pas afficher de données, ou au moins de choisir un moyen approprié pour afficher les messages potentiellement corrompus sans créer d'oracle et informer l'utilisateur que le courrier n'inspire pas confiance.



gpg a signalé une erreur; les applications ne respectent pas le contrat d'API. Je dois être d'accord avec les développeurs de GnuPG et ajouter: l'interface gpg était (et est toujours) une bombe à retardement car elle ne dit pas à l'utilisateur comment procéder. Au contraire, une action facile et apparemment bénéfique est mauvaise. Et une  API de ce  genresont malheureusement courants dans GnuPG.



Qu'est-ce qui fait une bonne API?



Réaliser ces deux choses - que l'API gpg est trop dogmatique et difficile à utiliser correctement - a façonné mes plans. Lorsque nous avons lancé le projet Sequoia, nous avons convenu que nous voulions éviter de telles erreurs. Sur la base de nos observations, nous avons mis en pratique deux tests que nous continuons à utiliser comme points de référence pour le développement de l'API Sequoia. Premièrement, en  plus de toute API de haut niveau, il doit y avoir une API de bas niveau qui n'est pas dogmatique - en ce sens qu'elle n'empêche pas l'utilisateur de faire quoi que ce soit qui n'est pas interdit. Dans le même temps, l'  API doit guider l'utilisateur vers les bonnes choses (codées en dur), rendant les bonnes actions faciles à exécuter et les plus évidentes lors du choix d'une action .



Pour atteindre ces deux objectifs légèrement contradictoires de rendre tout possible, mais de prévenir les erreurs, nous nous sommes particulièrement appuyés sur deux outils: les types et les exemples. Les types rendent difficile l'utilisation d'un objet de manière involontaire car le contrat d'API est formalisé au moment de la compilation et applique même des conversions spécifiques . Des exemples - des extraits de code - seront  copiés . Par conséquent, de bons exemples apprendront non seulement aux utilisateurs à utiliser correctement la fonction, mais auront également une grande influence sur la façon dont ils l'utiliseront.



Les types



Je vais vous montrer avec un exemple comment nous utilisons les types dans Sequoia et comment ils nous aident à créer une bonne API. Pour rendre l'exemple plus clair, il sera utile de rappeler un certain contexte concernant OpenPGP.





OpenPGP



Il existe plusieurs types de données fondamentaux dans OpenPGP, à savoir les certificats, les composants (tels que les clés et les ID utilisateur) et les signatures de liaison. La racine du certificat est la clé primaire qui identifie complètement l'empreinte digitale du certificat (fingerprint = Hash (clé primaire)). Un certificat comprend généralement des composants tels que des sous-clés et des ID utilisateur. OpenPGP lie un composant à un certificat à l'aide d'une soi-disant signature de liaison. Lorsque nous utilisons un hachage de clé primaire ordinaire comme empreinte digitale et que nous utilisons des signatures pour lier des composants à la clé primaire, des conditions sont créées afin que des composants supplémentaires puissent être ajoutés ultérieurement. Les signatures de liaison incluent également des propriétés. Par conséquent, il est possible de modifier le composant, par exemple pour prolonger la période de validité de la sous-clé.En conséquence, plusieurs signatures valides peuvent être associées à un composant particulier. Les signatures d'ancrage ne sont pas seulement fondamentales, mais font également partie intégrante du mécanisme de sécurité OpenPGP.



Puisqu'il peut y avoir de nombreuses signatures de liaison valides, il doit y avoir un moyen de sélectionner celle que vous voulez. En première approximation, supposons que la signature souhaitée soit la signature valide la plus récente, non expirée, non révoquée qui n'a pas été reportée pour le futur. Mais qu'est-ce qu'une signature valide? Chez Sequoia, la signature doit non seulement passer un contrôle mathématique, mais également être conforme à la politique. Par exemple, en raison de notre capacité à résister aux collisions compromises , nous  n'autorisons SHA-1 que dans un très petit nombre de situations . ( Paul Schaub , travaillant sur  PGPainless , a récemment  longuement écrit sur ces complexités..) En forçant l'utilisateur de l'API à garder toutes ces considérations à l'esprit, nous créons un terreau fertile pour les vulnérabilités. Dans Sequoia, le moyen le plus simple d'obtenir l'heure d'expiration est le moyen le plus sûr. Considérez le code suivant, qui fonctionne comme prévu:



let p = &StandardPolicy::new();
 
let cert = Cert::from_str(CERT)?;
for k in cert.with_policy(p, None)?.keys().subkeys() {
    println!("Key {}: expiry: {}",
             k.fingerprint(),
             if let Some(t) = k.key_expiration_time() {
                 DateTime::<Utc>::from(t).to_rfc3339()
             } else {
                 "never".into()
             });
}
      
      







cert



 Est un certificat. Nous commençons par lui appliquer la politique. (Les stratégies sont définies par l'utilisateur, mais en règle générale,  StandardPolicy est  non seulement suffisante mais également la plus appropriée). En fait, c'est là qu'une vue du certificat est créée, dans laquelle seuls les composants avec une signature de liaison valide sont visibles. Surtout, il modifie et introduit également un certain nombre de nouvelles méthodes. La méthode keys, par exemple, a été modifiée pour  renvoyer ValidKeyAmalgamation   au lieu de KeyAmalgamation . (Il s'agit d'une fusion, car le résultat inclut non seulement la clé, mais toutes les signatures qui lui sont associées; certains pensent que ce processus serait mieux appelé Katamari... ¯ \ _ (ツ) _ / ¯) ValidKeyAmalgamation a une signature d'ancrage valide selon les critères ci-dessus. Il fournit également des méthodes comme key_expiration_time, ce qui n'a de sens qu'avec une clé valide! Notez également que le type de retour utilisé avec key_expiration_time est ergonomique. Au lieu de renvoyer une valeur brute, key_expiration_time renvoie SystemTime , qui est sûr et facile à utiliser.



Conformément à notre premier principe «autoriser tout», le développeur conserve toujours l' accès aux signatures uniques  et  explore les sous-packagespour savoir à partir d'une liaison de signature différente lorsque la clé expire. Mais, par rapport à la façon dont l'API Sequoia est censée connaître correctement l'expiration d'une clé, toute autre approche contredirait l'API. C'est une bonne API à notre avis.



Exemples de



La version 1.0 de  la bibliothèque Sequoia a eu lieu en décembre 2020. Neuf mois avant cela, nous sommes entrés dans une situation de fonctionnalité complète et nous étions prêts pour la sortie. Mais ils ont attendu . Il nous a fallu neuf mois pour ajouter de la documentation et des exemples à l'API publique. Jetez un œil à la documentation de la structure de données Cert pour   un exemple, voyez ce que nous obtenons. Comme indiqué dans notre article, nous n'avons pas été en mesure de fournir des exemples pour chaque fonctionnalité jusqu'à un, mais nous en avons fait pas mal. En prime à l'écriture des exemples, nous avons également réussi à trouver quelques aspérités, que nous avons polies dans le processus.



Après la sortie, nous avons pu parler à de nombreux développeurs qui ont inclus Sequoia dans leur code. Un fil conducteur de leurs commentaires était la reconnaissance de l'utilité de la documentation et des exemples. Nous pouvons confirmer que bien que ce soit notre code, nous examinons la documentation presque quotidiennement et copions nos propres exemples. C'est plus facile. Puisque les exemples vous montrent comment utiliser correctement une fonction particulière, pourquoi recommencer à partir de zéro?



API RNP



RNP  est une nouvelle implémentation d'OpenPGP, développée principalement par Ribose . Il y a environ  deux ans , Thunderbird a décidé d'intégrer  Enigmail  dans Thunderbird et en même temps de  remplacer GnuPG par RNP . Le fait que Thunderbird ait choisi RNP n'est pas seulement flatteur pour RNP; cela signifie également que RNP est sans doute devenu l'implémentation d'OpenPGP la plus demandée pour le chiffrement du courrier.



La critique est facile à percevoir comme négative. Je veux être très clair: je pense que le travail que Ribose fait est bon et important, je leur suis reconnaissant d'avoir investi du temps et des efforts dans une nouvelle implémentation d'OpenPGP. L'écosystème OpenPGP a désespérément besoin d'ajouter de la variété. Mais ce n'est pas une excuse pour publier un produit immature pour une utilisation dans un contexte critique pour la sécurité.



Infrastructure critique pour la sécurité



Malheureusement, RNP n'a pas encore atteint un état où, à mon avis, il peut être déployé en toute sécurité. Enigmail a été utilisé non seulement par des personnes soucieuses de la confidentialité de leurs données, mais également par des journalistes, des militants et des avocats soucieux de leur propre sécurité et de celle de leurs interlocuteurs. Dans une interview en 2017, Benjamin Ismail, responsable de la section Asie-Pacifique de Reporters sans frontières , a déclaré:



Nous utilisons principalement GPG pour communiquer librement avec nos sources. Les informations qu'ils nous donnent sur les droits de l'homme et les violations de ces droits ne sont pas sans danger pour eux, il est donc nécessaire de protéger l'intégrité de nos conversations. 



Entretien avec Benjamin Ismail  de l'organisation  Reporters sans frontières



Il est essentiel que Thunderbird continue de fournir à ces utilisateurs l'expérience la plus sûre possible, même pendant cette période de transition.



Signatures de liaison RNP et sous-clé



En parlant de la façon dont nous utilisons les types dans Sequoia pour rendre plus difficile l'utilisation abusive de l'API, je vous ai montré comment connaître la date d'expiration d'une clé en quelques lignes de code. Je voulais commencer par un exemple montrant à une personne inexpérimentée en OpenPGP ou RNP comment la même fonctionnalité peut être implémentée en utilisant RNP. Le code suivant parcourt les sous-clés du certificat (clé) et affiche la date d'expiration de chaque sous-clé. Pour rappel, l'heure d'expiration est stockée dans la signature de liaison de sous-clé, et une valeur de 0 indique que la clé n'expirera jamais. 



int i;
for (i = 0; i < sk_count; i ++) {
  rnp_key_handle_t sk;
  err = rnp_key_get_subkey_at(key, i, &sk);
  if (err) {
    printf("rnp_key_get_subkey_at(%d): %x\n", i, err);
    return 1;
  }
 
  uint32_t expiration_time;
  err = rnp_key_get_expiration(sk, &expiration_time);
  if (err) {
    printf("#%d (%s). rnp_key_get_expiration: %x\n",
           i + 1, desc[i], err);
  } else {
    printf("#%d (%s) expires %"PRIu32" seconds after key's creation time.\n",
           i + 1, desc[i],
           expiration_time);
  }
}
      
      





J'ai testé ce code sur un certificat avec cinq sous-clés. La première sous-clé a une signature de liaison valide et n'expire pas; le second a une signature de liaison valide et expirera dans le futur; le troisième a une signature de liaison valide mais a déjà expiré; le quatrième a une signature de liaison invalide, selon laquelle la sous-clé expirera dans le futur; la cinquième signature n'a pas du tout d'ancrage. Voici le résultat:



#1 (doesn't expire) expires 0 seconds after key's creation time.

#2 (expires) expires 94670781 seconds after key's creation time.

#3 (expired) expires 86400 seconds after key's creation time.

#4 (invalid sig) expires 0 seconds after key's creation time.

#5 (no sig) expires 0 seconds after key's creation time.
      
      







Tout d'abord, notez que l'appel rnp_key_get_expiration réussit, que la sous-clé ait une signature de liaison valide, une signature de liaison non valide ou aucune signature de liaison du tout. Si vous lisez la  documentation , ce comportement semble un peu surprenant. Ça dit: 



       .

 : 0 ,     .

      
      





Étant donné que le délai d'expiration de la clé est stocké dans la signature de liaison, en tant qu'expert OpenPGP, je le comprends de cette façon: un appel à rnp_key_get_expiration ne réussira que si la sous-clé a une signature de liaison valide. En fait, il s'avère que s'il n'y a pas de signature de liaison valide, la fonction prend simplement la valeur par défaut 0, ce que, compte tenu de la remarque ci-dessus, l'utilisateur de l'API s'attend à interpréter comme suit: cette clé est valable indéfiniment.



Pour améliorer ce code, vous devez d'abord vérifier si la clé a une signature de liaison valide. Plusieurs fonctions pour faire exactement cela ont été récemment ajoutées à RNP pour adresser  CVE-2021-23991 . En particulier, les développeurs RNP a ajouté la fonction rnp_key_is_valid pour renvoyer des informations sur la validité d'une clé. Cet add-on améliore la situation, mais oblige le développeur à choisir explicitement si ces vérifications critiques de sécurité doivent être effectuées (plutôt que d'abandonner explicitement les vérifications déjà définies - comme ce serait le cas avec Sequoia). Parce que les contrôles de sécurité ne consistent pas à faire un travail utile, il est facile de les oublier: le code fonctionne même si aucun contrôle de sécurité n'a été effectué. Et comme il faut des connaissances spécialisées pour faire le bon choix de ce qu'il faut vérifier, les chèques sont oubliés.



Le code suivant fournit des contrôles de sécurité et ignore toutes les clés jugées invalides par rnp_key_is_valid:



int i;
for (i = 0; i < sk_count; i ++) {
  rnp_key_handle_t sk;
  err = rnp_key_get_subkey_at(key, i, &sk);
  if (err) {
    printf("rnp_key_get_subkey_at(%d): %x\n", i, err);
    return 1;
  }
 
  bool is_valid = false;
  err = rnp_key_is_valid(sk, &is_valid);
  if (err) {
    printf("rnp_key_is_valid: %x\n", err);
    return 1;
  }
 
  if (! is_valid) {
    printf("#%d (%s) is invalid, skipping.\n",
           i + 1, desc[i]);
    continue;
  }
 
  uint32_t expiration_time;
  err = rnp_key_get_expiration(sk, &expiration_time);
  if (err) {
    printf("#%d (%s). rnp_key_get_expiration: %x\n",
           i + 1, desc[i], err);
  } else {
    printf("#%d (%s) expires %"PRIu32" seconds after key's creation time.\n",
           i + 1, desc[i],
           expiration_time);
  }
}

      
      







Production:



#1 (doesn't expire) expires 0 seconds after key's creation time.

#2 (expires) expires 94670781 seconds after key's creation time.

#3 (expired) is invalid, skipping.

#4 (invalid sig) is invalid, skipping.

#5 (no sig) is invalid, skipping.
      
      







Ce code ignore correctement deux clés qui n'ont pas de signature de liaison valide, mais il ignore également une clé expirée - ce qui n'est probablement pas ce que nous voulions, même si la documentation nous avertit que cette fonction "vérifie ... les dates d'expiration".



Bien qu'il arrive également que nous ne souhaitions pas utiliser une clé ou un certificat expiré, nous y avons parfois recours. Par exemple, si un utilisateur oublie de renouveler la clé, il devrait être en mesure de voir que la clé a expiré, puis de vérifier le certificat et également de renouveler la clé dans ce cas. Bien qu'il gpg --list-keys



 n'affiche pas les clés expirées, lors de la modification d'un certificat, les sous-clés expirées sont toujours visibles, afin que l'utilisateur puisse renouveler leur validité:



$ gpg --edit-key 93D3A2B8DF67CE4B674999B807A5D8589F2492F9

Secret key is available.

sec  ed25519/07A5D8589F2492F9

     created: 2021-04-26  expires: 2024-04-26  usage: C   

     trust: unknown       validity: unknown

ssb  ed25519/1E2F512A0FE99515

     created: 2021-04-27  expires: never       usage: S   

ssb  cv25519/8CDDC2BC5EEB61A3

     created: 2021-04-26  expires: 2024-04-26  usage: E   

ssb  ed25519/142D550E6E6DF02E

     created: 2021-04-26  expired: 2021-04-27  usage: S   

[ unknown] (1). Alice <alice@example.org>
      
      







Il existe d'autres situations dans lesquelles une clé expirée ne doit pas être invalidée. Supposons, par exemple, qu'Alice envoie à Bob un message signé: "Je vous paierai 100 euros pendant un an" et que la clé de signature expire dans six mois. À la fin de l'année, Alice devra-t-elle à Bob sur la base de cette signature? Oui, je pense. La signature était valide lorsqu'elle a été apposée. Le fait que la clé a déjà expiré est sans importance. Bien entendu, lorsque la clé a expiré, les signatures scellées par celle-ci après le moment de son expiration doivent être considérées comme invalides. De même, un message ne doit pas être chiffré avec une clé expirée.



En bref, la question de savoir si une clé doit être considérée comme valide est très sensible au contexte. rnp_key_is_valid vaut mieux que rien, mais malgré le nom, cette fonction est assez nuancée pour déterminer si une clé est valide.



Dans le cadre de cette validation, la deuxième fonction a été ajoutée  rnp_key_valid_till



. Cette fonction renvoie "un horodatage avant lequel la clé peut être considérée comme valide ... Si la clé n'a jamais été valide, zéro est renvoyé comme valeur". En utilisant cette fonction, vous pouvez déterminer si la clé a jamais été valide, pour cela, vous devez vérifier si cette fonction renvoie une valeur non nulle:



int i;
for (i = 0; i < sk_count; i ++) {
  rnp_key_handle_t sk;
  err = rnp_key_get_subkey_at(key, i, &sk);
  if (err) {
    printf("rnp_key_get_subkey_at(%d): %x\n", i, err);
    return 1;
  }
 
  uint32_t valid_till;
  err = rnp_key_valid_till(sk, &valid_till);
  if (err) {
    printf("rnp_key_valid_till: %x\n", err);
    return 1;
  }
 
  printf("#%d (%s) valid till %"PRIu32" seconds after epoch; ",
         i + 1, desc[i], valid_till);
 
  if (valid_till == 0) {
    printf("invalid, skipping.\n");
    continue;
  }
 
  uint32_t expiration_time;
  err = rnp_key_get_expiration(sk, &expiration_time);
  if (err) {
    printf("rnp_key_get_expiration: %x\n", err);
  } else {
    printf("expires %"PRIu32" seconds after key's creation time.\n",
           expiration_time);
  }
}
      
      







Résultats:



#1 (doesn't expire) valid till 1714111110 seconds after epoch; expires 0 seconds after key's creation time.

#2 (expires) valid till 1714111110 seconds after epoch; expires 94670781 seconds after key's creation time.

#3 (expired) valid till 1619527593 seconds after epoch; expires 86400 seconds after key's creation time.

#4 (invalid sig) valid till 0 seconds after epoch; invalid, skipping.

#5 (no sig) valid till 0 seconds after epoch; invalid, skipping.
      
      







Nous avons maintenant les résultats que nous voulions! Nous affichons les délais d'expiration corrects pour les trois premières sous-clés et indiquons également que les deux dernières sous-clés ne sont pas valides.



Mais regardons de plus près  rnp_key_valid_till



. Premièrement, dans OpenPGP, l'heure d'expiration de la clé est stockée sous la forme d'un retrait 32 bits non signé à partir du moment où la clé a été créée, également au format 32 bits non signé. Par conséquent, la fonction devrait utiliser un type plus large, ou au moins vérifier le code pour les débordements. (J'ai  signalé ce problème et il a déjà été résolu.)



Mais, même si nous ignorons ce montant, la fonction est toujours étrange. Dans OpenPGP, une clé peut être valide pendant plusieurs périodes. Supposons que la clé expire le 1er juillet et que l'utilisateur ne la renouvelle qu'à partir du 10 juillet. Pendant la période du 1er au 10 juillet, la clé était invalide et les signatures générées pendant cette période devraient également être considérées comme invalides. Alors, que doit renvoyer la fonction considérée pour une telle clé? Plus important encore, comment un utilisateur d'une telle API devrait-il interpréter le résultat? Est-il approprié d'utiliser une telle API? ( Oui, j'ai demandé .)



Chez Sequoia, nous sommes allés dans l'autre sens. Au lieu de renvoyer des informations indiquant que la clé est valide, nous inversons la situation; L'utilisateur de l'API peut demander:  Cette clé est-elle valide au temps t . D'après notre expérience, c'est tout ce qui était réellement nécessaire dans tous les cas connus.



Ne pensez pas que je m'intéresse spécifiquement à ce problème particulier avec l'API RNP. C'est juste une complication à laquelle je pensais récemment. Lorsque nous avons réimplémenté l'API RNP pour créer  un backend OpenPGP alternatif  pour Thunderbird, nous avons été confrontés à de  nombreux problèmes similaires .



Conclusion



Les erreurs commises par les développeurs RNP sont compréhensibles et excusables. OpenPGP est complexe, comme de nombreux autres protocoles. Mais cela peut être grandement simplifié si nous nous efforçons de garder une PKI flexible et fiable , et pas seulement d'avoir un outil de cryptage de fichiers. 



Cependant, l'API RNP est dangereuse. Thunderbird est  utilisé  dans des contextes critiques pour la sécurité. Dans une interview en 2017Michal 'Rysiek' Wozniak  du Centre de recherche sur le crime organisé et la corruption (OCCRP) a clairement indiqué que la vie de quelqu'un était en jeu:



Je crois fermement que si nous n'avions pas utilisé GnuPG pendant tout ce temps, beaucoup de nos informateurs et journalistes seraient en danger ou derrière les barreaux ...



Entretien  avec  Michal 'Rysiek' Wozniak du Centre d'étude de la corruption et organisé la criminalité



Comment cela affectera-t-il Thunderbird? Je vois trois options. Premièrement, Thunderbird pourrait revenir à Enigmail. Vous pourriez penser que le portage d'Enigmail sur Thunderbird 78 serait difficile, mais j'ai entendu de nombreux développeurs Thunderbird dire que cela est techniquement faisable avec un ascenseur. Mais l'une des raisons pour lesquelles Thunderbird a choisi de s'éloigner d'Enigmail est le temps énorme que les développeurs d'Enigmail ont dû consacrer à aider les utilisateurs à installer et à configurer correctement GnuPG. Par conséquent, ce chemin n'est pas idéal.



Deuxièmement, Thunderbird pourrait passer à une autre implémentation d'OpenPGP. Il y en a tout un tas de nos jours.   à choisir. Personnellement, je pense que Thunderbird aurait dû passer à Sequoia. Bien sûr, je suis un développeur Sequoia, donc je suis partial. Mais ce n'est pas une question d'argent: le fonds me paie, et sur le marché libre, on me proposerait peut-être deux fois plus que ce que je gagne actuellement. Je travaille pour protéger les utilisateurs. Mais, même en dehors de l'API Sequoia et des avantages de l'implémentation, Thunderbird gagne également dans ce cas sur un autre point: nous avons déjà fait fonctionner cette implémentation. Il y a quelques semaines, nous avons sorti Octopus , un backend OpenPGP alternatif pour Thunderbird. Il a non seulement une parité fonctionnelle avec RNP, mais a également un certain nombre de fonctionnalités auparavant manquantes, par exemple, l'intégration avec gpg, ainsi que corrigé certaines failles de sécurité et rempli plusieurs exigences non fonctionnelles.



Troisièmement, Thunderbird aurait pu arrêter complètement d'utiliser OpenPGP. Cette décision ne me convient pas. Mais à plusieurs reprises, j'ai été préoccupé par la sécurité des utilisateurs les plus vulnérables de Thunderbird, et je pense que ne pas fournir du tout de support OpenPGP est peut-être encore plus sûr que le statu quo.






Macleod VPS est idéal pour le développement d'API.



Inscrivez-vous en utilisant le lien ci-dessus ou en cliquant sur la bannière et bénéficiez d'une remise de 10% pour le premier mois de location d'un serveur de toute configuration!






All Articles