19 komentáře “How to make Apache HttpClient trust Let’s Encrypt Certificate Authority

  1. Few notes:

    First, the issue is missing DST certificate in trust store. Adding the DST certificate is more future-proof, because LE might switch from one intermediate CA to another one in case of some unfortunate event. Note that the issue is related to Java rather than to Apache HttpClient: https://community.letsencrypt.org/t/will-the-cross-root-cover-trust-by-the-default-list-in-the-jdk-jre/134/2

    Second, there is an alternative (at least for Debian): You can install ca-certificates-java. Your Java CAs will be imported from OS then. (OK, these alternatives have their pros and cons. If adding a file to $JAVA_HOME/jre/lib/security/cacerts is too complicated, then ca-certificates-java will be probably also too complicated.)

  2. V aktuálních verzích Apache HTTP Client není nutné vytvářet vlastní implementace TrustManageru apod., vše už je implementováno:

    File certFile = …;

    SSLContext sslContext = SSLContexts
    .custom()
    .useProtocol(„TLSv1“)
    .loadTrustMaterial(certFile)
    .build();

    this.httpClient = HttpClients
    .custom()
    .setSSLContext(sslContext)
    .build();

    • Pro jistotu ještě importy:

      import org.apache.http.impl.client.HttpClients;
      import org.apache.http.ssl.SSLContexts;

    • Toto bohužel nefunguje – takto nahozený SSLContext správně zvaliduje pouze certifikáty uvnitř certFile v metodě .loadTrustMaterial, ale není tam už ten fallback na defaultní certifikáty v Java truststore.

      Totot jsem si teď prakticky znovu ověřil pomocí testů.

      • Ano, ale to je záměr 🙂 Nechci důvěřovat certifikátům ze systémového úložiště, protože nevím, které certifikáty tam jsou, a které tam budou s jinou verzí JRE.

        Chápu, že někomu to takhle může vyhovovat, ale osobně to nedoporučuju – jste pak závislí na tom, jaké certifikáty se dodavatel JRE zrovna rozhodne přibalit. Proto si raději udělám vlastní úložiště s certifikáty, které potřebuju – a u kterých mám jistotu, že je tam budu mít i za měsíc, až vyjde aktualizace JRE.

      • Chápu – v mém případě byla geneze taková, že pro produkci jsem pro správnou funkcionalitu REST clienta nemusel dělat nic – produkční servery měly certifikát od „standardních“ autorit.

        Stejný kód na testu / preprodukci ovšem padal, protože tam byl certifikát od Let’s Encrypt. Tj. chtěl jsem jen ošéfovat funkcionalitu pro test.

        Ale dobrý argument a budu na něj myslet!

    • No jestli správně chápu: http://stackoverflow.com/questions/5871279/java-ssl-and-cert-keystore

      „javax.net.ssl.trustStore – Location of the Java keystore file containing the collection of CA certificates trusted by this application process (trust store). If a trust store location is not specified using this property, the SunJSSE implementation searches for and uses a keystore file in default Java locations.“

      Tak tím sice vyřešíš Let’s Encrypt, ale odřízneš si cestu k těm zapečeným CA uvnitř Java trust storu ne?

      A druhý argument je opět to, že bys to musel nasetupovat na všech prostředích + tím ovlivníš celou JVM, což ne vždycky chceš.

      A navíc se to blbě testuje 🙂

      Má to ale tu výhodu, že to můžeš hodit na Operations 🙂

      • Novou certifikační autoritu lze přidat k těm systémovým (ať už úpravou toho systémového úložiště, nebo jeho kopií, přidáním nové CA a odkázáním přes tu systémovou proměnnou).

        Já v tom vidím jiný problém – touhle úpravou měním globálně certifikační autority pro celou Javu, a když používám systémové úložiště autorit, musí všechny části aplikace důvěřovat těm samým autoritám. To se mi z hlediska bezpečnosti nelíbí. Když má jedna služba komunikovat s nějakým HTTPS serverem, předám jí truststore s certifikátem jedné CA nebo přímo certifikátem serveru, a nechci tam mít povolené žádné jiné autority. Druhá služba pak bude komunikovat s jiným HTTPS serverem, a bude mít zase jiný truststore pouze s certifikáty, které potřebuje.

        Mám třeba ne moc významnou službu, která komunikuje se serverem, který má certifikát vydaný privátní autoritou provozovatele té služby. OK, pro tu službu mi to nevadí, ta firma může vydáním špatného certifikátu hacknout maximálně sama sebe. Ale nemůžu jejich CA důvěřovat i pro ostatní služby, protože pak by mohla hacknout i ty.

  3. Vsechno jasny az na:

    public X509Certificate[] getAcceptedIssuers() {
    return this.fallbackTrustManager.getAcceptedIssuers();
    }

    tady nepotrebujes slozeninu z mainTrustManageru a fallbackTrustManageru ?

    • Asi by bylo možná vhodné udělat join polí z obou TrustManagerů – nicméně nikde jsem nenašel, k čemu se tato metoda používá (v HttpClientu vůbec) a evidentně to nemá na funkci rostlináře žádný vliv. 🙂

      • Tohle se používá na serveru při přihlášení klientským certifikátem. Když server vyžaduje přihlášení klientským certifikátem, může klientovi poslat seznam autorit, jejichž certifikáty akceptuje. Typicky webový prohlížeč dává uživateli na výběr, který certifikát se má pro přihlášení použít, a podle tohohle seznamu certifikáty vyfiltruje.

        V tomhle je to rozhraní hloupě navržené, protože míchá dohromady klientský a serverový kód. Ale bacha při implementaci, doporučuju implementovat všechny metody, i když implementujete jen klienta a nějaká metoda by měla být určená jen pro server. Měl jsem to implementované tak, že serverové metody vyhazovaly nějakou unsupported výjimku, a pak myslím s Javou 7 najednou aplikace začala padat, protože v rámci jakéhosi bezpečnostního vylepšení začali volat i na klientovi některé serverové metody.

    • Přesně tohle píšu v třetím odstavci článku. Protože pokud máte cluster, dev, test a prod prostředí, tak to musíte obejít všechno. Tento způsob se dá jednoduše přibalit do aplikace, pokrýt testy a mít jistotu 🙂

      • No ale kdo dnes obchází stroje a ručně na nich něco mění? 🙂 To stačí zadat jednou do Puppetu/Ansiblu/Chefu a hotovo, ne? 🙂

      • Dobrá připomínka – tady asi narážíme na to, že Chef si u nás spravují kluci z Operations a je to pro mě komplikovanější varianta, než výše popsaná věc.

Napsat komentář