Thunderbird, RNP y la importancia de una buena API





Recientemente tuve una charla con un desarrollador de  Thunderbird  sobre el diseño de API. Durante esta conversación, compartí mis pensamientos sobre RNP , una  nueva implementación de OpenPGP que Thunderbird comenzó a usar recientemente en lugar de GnuPG .



El interlocutor se mostró escéptico sobre mi tesis de que la API de RNP necesita mejoras y preguntó: "¿No es subjetivo, qué API es mejor y cuál es peor?" Estoy de acuerdo en que no tenemos buenas métricas para evaluar las API. Pero no estoy de acuerdo con que, en principio, no podamos juzgar la API.



De hecho, sospecho que los programadores más experimentados reconocerán una API incorrecta si la ven. Creo que más adelante en este artículo resultará desarrollar una buena heurística, que intentaré basarme en mi propia experiencia con (y más) GnuPG,  Sequoiay RNP. Luego, repasaré la API de RNP. Desafortunadamente, esta API no solo se puede usar incorrectamente con facilidad, sino que también es engañosa, por lo que aún no debe usarse en contextos críticos para la seguridad. Pero el público objetivo de Thunderbird son personas conocidas por ser vulnerables, como periodistas, activistas, abogados y sus socios de comunicación; todas estas personas necesitan protección. En mi opinión, esto significa que Thunderbird debería pensar una vez más sobre si usar RNP.



Nota: También sugiero leer este correo electrónico:  ¡Usemos bibliotecas GPL en Thunderbird! que envié  a la publicación Thunderbird Development Planning .



¿Cuáles son las características de una API incorrecta?



Antes de comenzar Sequoia con Justus y Kai  , los tres trabajamos en GnuPG . No solo profundizamos en gpg, sino que también hablamos y colaboramos con muchos usuarios posteriores de gpg. La gente pudo decir  muchas cosas buenas sobre GnuPG .





En lo que respecta a las críticas a gpg, las más significativas fueron dos tipos de críticas sobre la API. La primera se reduce a esto: la API de gpg es demasiado dogmática. Por ejemplo, gpg utiliza un enfoque de llavero. Por lo tanto, solo puede ver o usar un certificado OpenPGP si se ha importado a la base de claves personal. Pero algunos desarrolladores quieren ver el certificado primero y solo luego importarlo. Por ejemplo, cuando busca un certificado en un servidor de claves por su huella digital, puede verificar y asegurarse de que el certificado devuelto sea realmente el que necesita.porque su URL se autentica automáticamente. Esto se puede hacer usando gpg, pero solo de una manera alternativa, pasando por alto los principios del modelo de programación que está incrustado en él. La idea básica es la siguiente: cree un directorio temporal, agregue un archivo de configuración, dígale a gpg que use un directorio alternativo, importe el certificado allí, verifique el certificado y luego borre el directorio temporal. Esta es una recomendación oficial agregada por  Justus  basada en nuestras conversaciones con los usuarios posteriores de gpg. Sí, este método funciona. Pero requiere escribir un código que es específico del sistema operativo, este código es lento y a menudo se introducen errores en él.



Otra clase de comentarios con los que nos hemos encontrado muchas veces es que para trabajar con gpg, es necesario saber muchas cosas que no son obvias, para no abusar de este mecanismo. O, para decirlo de otra manera, debe tener mucho cuidado al usar la API de gpg para evitar introducir inadvertidamente una vulnerabilidad en su código.



Para comprender mejor la segunda preocupación, considere las vulnerabilidades de EFAIL... El principal problema con la API de descifrado de gpg: al descifrar un mensaje, gpg dará texto sin formato, incluso si la entrada está dañada. gpg devuelve un error en este caso, pero algunos programas aún generan texto sin formato en una forma corrupta. ¿Entonces por qué no? Definitivamente es mejor mostrar al menos parte del mensaje que no mostrar nada, ¿verdad? Bueno, las vulnerabilidades de EFAIL demuestran cómo un atacante puede aprovechar esto para inyectar un error web  en un mensaje cifrado. Cuando un usuario ve esta publicación, se filtra un error web de la publicación. Uf.



Entonces, ¿de quién es la culpa este error? Los desarrolladores de  GnuPG   insistieron en que el problema está en el nivel de la aplicación, ya que usan gpg incorrectamente:



se recomienda que los agentes de usuario de correo respeten el código de estado DECRYPTION_FAILED y no muestren datos, o al menos elijan una forma adecuada de mostrar el correo potencialmente dañado sin crear un oráculo y informar al usuario que el correo no inspira confianza.



gpg señaló un error; las aplicaciones no cumplen con el contrato de API. Tengo que estar de acuerdo con los desarrolladores de GnuPG y agregar: la interfaz de gpg era (y sigue siendo) una bomba de tiempo porque no le dice al usuario cómo proceder. Por el contrario, una acción fácil y aparentemente beneficiosa está mal. Y una  API de este  tipodesafortunadamente son comunes en GnuPG.



¿Qué hace que una API sea buena?



Darme cuenta de estas dos cosas, que la API de gpg es demasiado dogmática y difícil de usar correctamente, dio forma a mis planes. Cuando iniciamos el proyecto Sequoia, estuvimos de acuerdo en que queríamos evitar esos errores. A partir de nuestras observaciones, ponemos en práctica dos pruebas que seguimos utilizando como puntos de referencia para el desarrollo de la API de Sequoia. Primero,  además de cualquier API de alto nivel, debe haber una API de bajo nivel que no sea dogmática, en el sentido de que no impide que el usuario haga algo que no esté prohibido. Al mismo tiempo, la  API debe guiar al usuario hacia las cosas correctas (codificadas), haciendo que las acciones correctas sean fáciles de ejecutar y más obvias al elegir una acción .



Para lograr estos dos objetivos ligeramente contradictorios de hacer todo posible, pero evitando errores, nos hemos apoyado especialmente en dos herramientas: tipos y ejemplos. Los tipos dificultan el uso de un objeto de forma involuntaria porque el contrato de API se formaliza en el momento de la compilación e incluso impone conversiones específicas . Se copiarán ejemplos (fragmentos de código)  . Por lo tanto, los buenos ejemplos no solo enseñarán a los usuarios cómo usar la función correctamente, sino que también influirán en gran medida en cómo la usarán.



Tipos



Te mostraré con un ejemplo cómo usamos los tipos en Sequoia y cómo nos ayudan a crear una buena API. Para aclarar el ejemplo, será útil recordar algo de contexto sobre OpenPGP.





OpenPGP



Hay varios tipos de datos fundamentales en OpenPGP, a saber, certificados, componentes (como claves e ID de usuario) y firmas vinculantes. La raíz del certificado es la clave principal que identifica completamente la huella digital del certificado (huella digital = Hash (clave principal)). Un certificado generalmente incluye componentes como subclaves e ID de usuario. OpenPGP vincula un componente a un certificado mediante la denominada firma vinculante. Cuando usamos un hash de clave primaria regular como huella digital y usamos firmas para vincular componentes a la clave primaria, se crean condiciones para que más tarde se puedan agregar componentes adicionales. Las firmas vinculantes también incluyen propiedades. Por lo tanto, es posible cambiar el componente, por ejemplo, para extender el período de validez de la subclave.Como consecuencia, se pueden asociar varias firmas válidas con un componente en particular. Las firmas de anclaje no solo son fundamentales, sino que también son parte integral del mecanismo de seguridad de OpenPGP.



Dado que puede haber muchas firmas vinculantes válidas, debe haber una forma de seleccionar la que desee. Como primera aproximación, suponga que la firma que queremos es la firma válida más reciente, no vencida y no revocada que no se ha pospuesto para el futuro. Pero, ¿qué es una firma válida? En Sequoia, la firma no solo debe pasar una verificación matemática, sino que también debe ser coherente con la política. Por ejemplo, debido a nuestra capacidad para resistir colisiones comprometidas , solo  permitimos SHA-1 en una cantidad muy pequeña de situaciones . ( Paul Schaub , trabajando en  PGPainless , recientemente  escribió extensamente sobre estas complejidades..) Al obligar al usuario de la API a tener en cuenta todas estas consideraciones, creamos un caldo de cultivo para las vulnerabilidades. En Sequoia, la forma más fácil de obtener el tiempo de vencimiento es la forma segura. Considere el siguiente código, que funciona como se esperaba:



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



 Es un certificado. Comenzamos aplicándole la política. (Las políticas son definidas por el usuario, pero como regla,  StandardPolicy  no solo es suficiente sino también la más apropiada). De hecho, aquí es donde se crea una vista del certificado, en la que solo son visibles los componentes con una firma vinculante válida. Es importante destacar que también modifica e introduce varios métodos nuevos. El método de claves, por ejemplo, se ha cambiado para  devolver ValidKeyAmalgamation en   lugar de KeyAmalgamation . (Esta es una fusión, ya que el resultado incluye no solo la clave, sino todas las firmas asociadas con ella; algunos creen que este proceso se llamaría mejor Katamari... ¯ \ _ (ツ) _ / ¯) ValidKeyAmalgamation tiene una firma de ancla válida de acuerdo con los criterios anteriores. También proporciona métodos como key_expiration_time, que solo tiene sentido con una clave válida. También tenga en cuenta que el tipo de retorno utilizado con key_expiration_time es ergonómico. En lugar de devolver un valor sin procesar, key_expiration_time devuelve SystemTime , que es seguro y fácil de usar.



De acuerdo con nuestro primer principio de "permitir todo", el desarrollador aún conserva el acceso a firmas únicas  y  explora los subpaquetes.para averiguar a partir de un enlace de firma diferente cuándo caduca la clave. Pero, en comparación con la forma en que se supone que la API de Sequoia conoce correctamente la expiración de una clave, cualquier otro enfoque contradeciría la API. Esta es una buena API en nuestra opinión.



Ejemplos de



La versión 1.0 de  la biblioteca Sequoia tuvo lugar en diciembre de 2020. Nueve meses antes de eso, entramos en una situación de características completas y estábamos listos para su lanzamiento. Pero esperaron . Nos tomó los siguientes nueve meses agregar documentación y ejemplos a la API pública. Eche un vistazo a la documentación de la estructura de datos de Cert para ver   un ejemplo, vea lo que obtenemos. Como se señaló en nuestra publicación, no pudimos proporcionar ejemplos para cada función hasta una, pero lo hicimos bastante. Como beneficio adicional de escribir los ejemplos, también logramos encontrar algunos bordes ásperos, que pulimos en el proceso.



Después del lanzamiento, pudimos hablar con muchos de los desarrolladores que incluyeron Sequoia en su código. Un hilo común a través de sus comentarios fue el reconocimiento de cuán útiles fueron tanto la documentación como los ejemplos. Podemos confirmar que aunque este es nuestro código, miramos la documentación casi a diario y copiamos nuestros propios ejemplos. Es mas fácil. Dado que los ejemplos le muestran cómo usar una función en particular correctamente, ¿por qué volver a hacerlo desde cero?



API de RNP



RNP  es una nueva implementación de OpenPGP, desarrollada principalmente por Ribose . Hace aproximadamente  dos años , Thunderbird decidió integrar  Enigmail  en Thunderbird y al mismo tiempo  reemplazar GnuPG con RNP . El hecho de que Thunderbird eligiera RNP no solo es halagador para RNP; también significa que RNP se ha convertido posiblemente en la implementación más solicitada de OpenPGP para cifrar correo.



La crítica es fácil de percibir como negativa. Quiero ser muy claro: creo que el trabajo que está haciendo Ribose es bueno e importante, les agradezco por invertir tiempo y esfuerzo en una nueva implementación de OpenPGP. El ecosistema OpenPGP necesita desesperadamente agregar variedad. Pero esto no es una excusa para lanzar un producto inmaduro para su uso en un contexto crítico para la seguridad.



Infraestructura crítica para la seguridad



Desafortunadamente, RNP aún no ha alcanzado un estado en el que, en mi opinión, se pueda implementar de forma segura. Enigmail fue utilizado no solo por personas preocupadas por la privacidad de sus datos, sino también por periodistas, activistas y abogados que se preocupan por su propia seguridad y la seguridad de sus interlocutores. En una entrevista de 2017, Benjamin Ismail, director del capítulo Asia-Pacífico de Reporteros sin Fronteras , dijo:



Utilizamos principalmente GPG para comunicarnos libremente con nuestras fuentes. La información que nos brindan sobre derechos humanos y violaciones de estos derechos no es segura para ellos, por lo que es necesario proteger la integridad de nuestras conversaciones. 



Entrevista a Benjamin Ismail  de la organización  Reporteros sin fronteras



Es fundamental que Thunderbird continúe brindando a estos usuarios la experiencia más segura posible, incluso durante este período de transición.



Firmas de enlace de subclave y RNP



Al hablar sobre cómo usamos los tipos en Sequoia para dificultar el uso indebido de la API, le mostré cómo averiguar la fecha de vencimiento de una clave en solo unas pocas líneas de código. Quería comenzar con un ejemplo que le demostrara a una persona sin experiencia en OpenPGP o RNP cómo se puede implementar la misma funcionalidad usando RNP. El siguiente código itera sobre las subclaves del certificado (clave) y muestra la fecha de vencimiento de cada subclave. Como recordatorio, el tiempo de caducidad se almacena en la firma de enlace de subclave y un valor de 0 indica que la clave nunca caducará. 



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);
  }
}
      
      





Probé este código en un certificado con cinco subclaves. La primera subclave tiene una firma de enlace válida y no caduca; el segundo tiene una firma vinculante válida y caducará en el futuro; el tercero tiene una firma vinculante válida pero ya ha caducado; el cuarto tiene una firma de enlace no válida, según la cual la subclave caducará en el futuro; la quinta firma no tiene anclaje en absoluto. Aquí está el resultado:



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







Primero, tenga en cuenta que la llamada rnp_key_get_expiration se realiza correctamente, independientemente de si la subclave tiene una firma de vinculación válida, una firma de vinculación no válida o ninguna firma de vinculación. Si lee la  documentación , este comportamiento parece un poco sorprendente. Dice: 



       .

 : 0 ,     .

      
      





Dado que el tiempo de caducidad de la clave se almacena en la firma de enlace, como experto en OpenPGP lo entiendo de esta manera: una llamada a rnp_key_get_expiration solo tendrá éxito si la subclave tiene una firma de enlace válida. De hecho, resulta que si no hay una firma de enlace válida, entonces la función simplemente toma el valor predeterminado de 0, lo que, dado el comentario anterior, el usuario de la API esperaría interpretar como: esta clave es válida indefinidamente.



Para mejorar este código, primero debe verificar si la clave tiene una firma vinculante válida. Varias funciones para hacer precisamente eso se agregaron recientemente a RNP para abordar  CVE-2021-23991 . En particular, los desarrolladores de RNP agregó la función rnp_key_is_valid para devolver información sobre si una clave es válida. Este complemento mejora la situación, pero requiere que el desarrollador elija explícitamente si se deben realizar estas comprobaciones críticas de seguridad (en lugar de abandonar explícitamente las comprobaciones ya establecidas, como sería el caso de Sequoia). Debido a que las comprobaciones de seguridad no sirven para realizar un trabajo útil, es fácil olvidarse de ellas: el código funciona incluso si no se han realizado comprobaciones de seguridad. Y dado que se necesita un conocimiento experto para tomar la decisión correcta de qué verificar, los controles se olvidan.



El siguiente código proporciona controles de seguridad y omite cualquier clave que rnp_key_is_valid considere inválida:



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);
  }
}

      
      







Producción:



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







Este código omite correctamente dos claves que no tienen una firma vinculante válida, pero también omite una clave caducada, que probablemente no sea lo que queríamos, aunque la documentación nos advierte que esta función "verifica ... fechas de caducidad".



Aunque también sucede que no queremos utilizar una clave o certificado caducado, en ocasiones recurrimos a ellos. Por ejemplo, si un usuario olvida renovar la clave, entonces debería poder ver que la clave ha caducado y luego verificar el certificado, y también renovar la clave en este caso. Aunque gpg --list-keys



 no muestra claves caducadas, al editar un certificado, las subclaves caducadas siguen siendo visibles, por lo que el usuario puede renovar su validez:



$ 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>
      
      







Hay otras situaciones en las que una clave caducada no debe invalidarse. Supongamos, por ejemplo, que Alice le envía a Bob un mensaje firmado: "Te pagaré 100 euros por un año", y la clave de firma caduca en seis meses. Cuando termine el año, ¿Alice le deberá a Bob en base a esta firma? Sí, eso creo. La firma era válida cuando se colocó. El hecho de que la clave ya haya caducado es irrelevante. Por supuesto, cuando la clave ha expirado, las firmas selladas por ella después del momento de su expiración deben considerarse inválidas. Del mismo modo, un mensaje no debe cifrarse con una clave caducada.



En resumen, si una clave debe considerarse válida es muy sensible al contexto. rnp_key_is_valid es mejor que nada, pero a pesar del nombre, esta función tiene muchos matices para determinar si una clave es válida.



Como parte de ese compromiso, se ha agregado la segunda función  rnp_key_valid_till



. Esta función devuelve "una marca de tiempo antes de la cual la clave puede considerarse válida ... Si la clave nunca fue válida, se devuelve cero como valor". Usando esta función, puede determinar si la clave alguna vez fue válida, para esto debe verificar si esta función devuelve un valor distinto de cero:



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);
  }
}
      
      







Resultados:



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







¡Ahora obtuvimos los resultados que queríamos! Mostramos los tiempos de vencimiento correctos para las tres primeras subclaves y también indicamos que las dos últimas subclaves no son válidas.



Pero echemos un vistazo más de cerca  rnp_key_valid_till



. Primero, en OpenPGP, el tiempo de caducidad de la clave se almacena como una sangría de 32 bits sin firmar desde el momento en que se creó la clave, también en formato de 32 bits sin firmar. Por lo tanto, la función tendría que usar un tipo más amplio, o al menos verificar el código en busca de desbordamientos. (  Informé de este problema y ya se ha solucionado).



Pero, incluso si ignoramos esta jamba, la función sigue siendo extraña. En OpenPGP, una clave puede ser válida durante varios períodos de tiempo. Digamos que la clave vence el 1 de julio y el usuario la renueva solo a partir del 10 de julio. Durante el período comprendido entre el 1 de julio y el 10 de julio, la clave no fue válida y las firmas generadas durante este período también deben considerarse inválidas. Entonces, ¿qué debería devolver la función considerada para tal clave? Más importante aún, ¿cómo debería un usuario de dicha API interpretar el resultado? ¿Es apropiado usar una API de este tipo? ( Sí, le pregunté ).



En Sequoia, fuimos por el otro lado. En lugar de devolver información de que la clave es válida, cambiamos la situación; El usuario de la API puede preguntar:  ¿Es esta clave válida en el tiempo t ? En nuestra experiencia, esto es todo lo que realmente se requirió en todos los casos que conocemos.



No piense que me estoy refiriendo específicamente a este problema en particular con la API de RNP. Esta es solo una complicación en la que estaba pensando recientemente. Cuando reimplementamos la API RNP para crear  un backend OpenPGP alternativo  para Thunderbird, enfrentamos  muchos problemas similares .



Conclusión



Los errores cometidos por los desarrolladores de RNP son comprensibles y excusables. OpenPGP es complejo, como muchos otros protocolos. Pero se puede simplificar enormemente si nos esforzamos por mantener una PKI flexible y confiable , y no solo por tener una herramienta de cifrado de archivos. 



Sin embargo, la API de RNP es peligrosa. Thunderbird se  utiliza  en contextos críticos para la seguridad. En una entrevista de 2017Michal 'Rysiek' Wozniak  del Centro para la Investigación del Crimen Organizado y la Corrupción (OCCRP) dejó en claro que la vida de alguien está en juego:



Realmente creo firmemente que si no hubiéramos estado usando GnuPG todo este tiempo, muchos de nuestros informantes y periodistas estarían en peligro o tras las rejas ...



Entrevista  con  Michal 'Rysiek' Wozniak del Centro para el Estudio de la Corrupción y Organizados Crimen



¿Cómo afectará esto a Thunderbird? Veo tres opciones. Primero, Thunderbird podría volver a Enigmail. Podría pensar que transferir Enigmail a Thunderbird 78 sería difícil, pero muchos desarrolladores de Thunderbird me han dicho que esto es técnicamente factible con un impulso. Pero una de las razones por las que Thunderbird decidió alejarse de Enigmail es la enorme cantidad de tiempo que los desarrolladores de Enigmail dedicaron a ayudar a los usuarios a instalar y configurar GnuPG correctamente. Por tanto, este camino no es el ideal.



En segundo lugar, Thunderbird podría cambiar a una implementación de OpenPGP diferente. Hay muchos de ellos hoy en día.   Para escoger de. Personalmente, creo que Thunderbird debería haberse cambiado a Sequoia. Por supuesto, soy un desarrollador de Sequoia, así que soy parcial. Pero no se trata de dinero: el fondo me paga, y en el mercado libre me ofrecerían, quizás, el doble de lo que gano ahora. Trabajo para proteger a los usuarios. Pero, incluso aparte de la API de Sequoia y los beneficios de la implementación, Thunderbird también gana en este caso en un aspecto más: ya hemos hecho que esta implementación funcione. Hace unas semanas lanzamos Octopus , un backend OpenPGP alternativo para Thunderbird. No solo tiene paridad funcional con RNP, sino que también tiene una serie de características que antes faltaban, por ejemplo, la integración con gpg, además de parchear algunos agujeros de seguridad y cumplir con varios requisitos no funcionales.



En tercer lugar, Thunderbird podría haber dejado de usar OpenPGP por completo. Esta decisión no me conviene. Pero en varias ocasiones me ha preocupado la seguridad de los usuarios más vulnerables de Thunderbird, y creo que no proporcionar ningún soporte de OpenPGP es quizás incluso más seguro que el status quo.






Los VPS de Macleod son ideales para el desarrollo de API.



Regístrese usando el enlace de arriba o haciendo clic en el banner y obtenga un 10% de descuento durante el primer mes de alquiler de un servidor de cualquier configuración.






All Articles