{"id":17685260,"url":"https://github.com/hakky54/sslcontext-kickstart","last_synced_at":"2026-01-11T17:01:18.539Z","repository":{"id":36968614,"uuid":"230795797","full_name":"Hakky54/sslcontext-kickstart","owner":"Hakky54","description":"🔐 A lightweight high level library for configuring a http client or server based on SSLContext or other properties such as TrustManager, KeyManager or Trusted Certificates to communicate over SSL TLS for one way authentication or two way authentication provided by the SSLFactory. Support for Java, Scala and Kotlin based clients with examples. Available client examples are: Apache HttpClient, OkHttp, Spring RestTemplate, Spring WebFlux WebClient Jetty and Netty, the old and the new JDK HttpClient, the old and the new Jersey Client, Google HttpClient, Unirest, Retrofit, Feign, Methanol, Vertx, Scala client Finagle, Featherbed, Dispatch Reboot, AsyncHttpClient, Sttp, Akka, Requests Scala, Http4s Blaze, Kotlin client Fuel, http4k Kohttp and Ktor. Also gRPC, WebSocket and ElasticSearch examples are included","archived":false,"fork":false,"pushed_at":"2025-05-07T20:57:24.000Z","size":4288,"stargazers_count":528,"open_issues_count":0,"forks_count":81,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-07T21:31:52.549Z","etag":null,"topics":["android","certificate","der","encryption","https","java","keymanagerfactory","keystore","kotlin","mutual-authentication","p12","p7b","pem","scala","security","ssl","sslcontext","tls","trustmanagerfactory","truststore"],"latest_commit_sha":null,"homepage":"https://sslcontext-kickstart.com/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hakky54.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["Hakky54"],"open_collective":"hakky54","ko_fi":"hakky54"}},"created_at":"2019-12-29T19:45:10.000Z","updated_at":"2025-05-07T20:57:27.000Z","dependencies_parsed_at":"2024-05-05T21:25:45.660Z","dependency_job_id":"ee1306e1-509b-49e6-9baa-6d1ec2efef92","html_url":"https://github.com/Hakky54/sslcontext-kickstart","commit_stats":{"total_commits":1267,"total_committers":15,"mean_commits":84.46666666666667,"dds":"0.21389108129439616","last_synced_commit":"9b4c48f57608e05ed3815021fd70a6880af11640"},"previous_names":[],"tags_count":84,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hakky54%2Fsslcontext-kickstart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hakky54%2Fsslcontext-kickstart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hakky54%2Fsslcontext-kickstart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hakky54%2Fsslcontext-kickstart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hakky54","download_url":"https://codeload.github.com/Hakky54/sslcontext-kickstart/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254029004,"owners_count":22002283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","certificate","der","encryption","https","java","keymanagerfactory","keystore","kotlin","mutual-authentication","p12","p7b","pem","scala","security","ssl","sslcontext","tls","trustmanagerfactory","truststore"],"created_at":"2024-10-24T10:27:09.863Z","updated_at":"2026-01-11T17:01:18.522Z","avatar_url":"https://github.com/Hakky54.png","language":"Java","readme":"[![Actions Status](https://github.com/Hakky54/ayza/workflows/Build/badge.svg)](https://github.com/Hakky54/ayza/actions)\n[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=io.github.hakky54%3Aayza-parent\u0026metric=security_rating)](https://sonarcloud.io/dashboard?id=io.github.hakky54%3Aayza-parent)\n[![Known Vulnerabilities](https://snyk.io/test/github/Hakky54/ayza/badge.svg)](https://snyk.io/test/github/Hakky54/ayza)\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=io.github.hakky54%3Aayza-parent\u0026metric=coverage)](https://sonarcloud.io/dashboard?id=io.github.hakky54%3Aayza-parent)\n[![JDK Compatibility](https://img.shields.io/badge/JDK_Compatibility-8+-blue.svg)](#)\n[![Kotlin Compatibility](https://img.shields.io/badge/Kotlin_Compatibility-1.5+-blue.svg)](#)\n[![Scala Compatibility](https://img.shields.io/badge/Scala_Compatibility-2.11+-blue.svg)](#)\n[![Android API Compatibility](https://img.shields.io/badge/Android_API_Compatibility-24+-blue.svg)](#)\n[![Apache2 license](https://img.shields.io/badge/license-Aache2.0-blue.svg)](https://github.com/Hakky54/ayza/blob/master/LICENSE)\n[![Maven Central](https://maven-badges.sml.io/sonatype-central/io.github.hakky54/ayza/badge.svg?style=flat\u0026subject=Sonatype%20Central\u0026color=blue)](https://central.sonatype.com/artifact/io.github.hakky54/ayza)\n[![Dependencies: none](https://img.shields.io/badge/dependencies-1-blue.svg)](#)\n[![GitHub stars chart](https://img.shields.io/badge/github%20stars-chart-blue.svg)](https://seladb.github.io/StarTrack-js/#/preload?r=hakky54,ayza)\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FHakky54%2Fayza.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2FHakky54%2Fayza?ref=badge_shield)\n\n[![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-white.svg)](https://sonarcloud.io/dashboard?id=io.github.hakky54%3Aayza-parent)\n\n# Ayza 🔐\nHey, hello there 👋 Welcome, I hope you will like this library. Feel free to drop a message in the [📖 Guestbook](https://github.com/Hakky54/ayza/discussions/302), I would love to hear your story and experience in using this library.\n\nI have created this library with ❤️ and passion, mostly during evening and night hours. If you use my library and want to appreciate the work I have done, please consider to sponsor this project as a way to contribute back to the community.\nThere are 3 options available to pick from: [GitHub](https://github.com/sponsors/Hakky54), [Ko-fi](https://ko-fi.com/hakky54) and [Open Collective](https://opencollective.com/hakky54)\n\n# Install library with:\n### Install with [Maven](https://mvnrepository.com/artifact/io.github.hakky54/ayza)\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.hakky54\u003c/groupId\u003e\n    \u003cartifactId\u003eayza\u003c/artifactId\u003e\n    \u003cversion\u003e10.0.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n### Install with Gradle\n```groovy\nimplementation 'io.github.hakky54:ayza:10.0.3'\n```\n### Install with Gradle Kotlin DSL\n```kotlin\nimplementation(\"io.github.hakky54:ayza:10.0.3\")\n```\n### Install with Scala SBT\n```\nlibraryDependencies += \"io.github.hakky54\" % \"ayza\" % \"10.0.3\"\n```\n### Install with Apache Ivy\n```xml\n\u003cdependency org=\"io.github.hakky54\" name=\"ayza\" rev=\"10.0.3\"/\u003e\n```\n\n## Table of contents\n1. [Introduction](#introduction)\n   - [History](#history)\n   - [Advantages](#advantages)\n   - [Definitions](#definitions)\n   - [Compatibility](#compatibility)\n2. [Usage](#usage)\n   - [Example configuration](#basic-example-configuration)\n   - [Other possible configurations](#other-possible-configurations)\n     - [Loading keystore from the classpath](#loading-keystore-and-truststore-from-the-classpath)\n     - [Loading keystore from the file system](#loading-keystore-and-trust-store-from-anywhere-on-the-filesystem)\n     - [Loading keystore from InputStream](#loading-keystore-and-trust-store-from-inputstream)\n     - [Loading trust material with OCSP options](#loading-trust-material-with-ocsp-options)\n         - [TrustStore from the classpath](#loading-trust-material-with-truststore-and-ocsp-options-from-the-classpath)\n         - [TrustStore from the file system](#loading-trust-material-with-truststore-and-ocsp-options-from-the-file-system)\n         - [TrustManager](#loading-trust-material-with-trustmanager-and-ocsp-options)\n         - [Certificates](#loading-trust-material-with-certificates-and-ocsp-options)\n     - [Enhanceable trust validations](#enhanceable-trust-validations)\n     - [Hide trusted certificate names of a server](#hide-trusted-certificate-names-of-a-server)\n     - [Skip certificate validation](#trusting-all-certificates-without-validation-not-recommended-to-use-at-production)\n     - [Skip hostname validation](#skip-hostname-validation)\n     - [Loading JDK and OS trusted certificates](#loading-jdk-and-os-trusted-certificates)\n     - [Using specific protocols and ciphers with custom secure-random and hostname-verifier](#using-specific-protocols-ciphers-with-custom-secure-random-and-hostname-verifier)\n     - [Enhanceable hostname verifier](#enhanceable-hostname-verifier)\n     - [Using multiple identity materials and trust materials](#support-for-using-multiple-identity-materials-and-trust-materials)\n     - [Using custom KeyManager and TrustManager](#support-for-using-x509extendedkeymanager-and-x509extendedtrustmanager)\n     - [Using dummy identity and trust material](#using-dummy-identity-and-trust-material)\n     - [Using KeyStore with multiple keys having different passwords](#support-for-using-a-single-keystore-which-contains-multiple-keys-with-different-passwords)\n     - [Using custom PrivateKey and Certificates](#support-for-using-privatekey-and-certificates)\n     - [Reloading SSL at runtime](#support-for-reloading-ssl-at-runtime)\n     - [Hot swap KeyManager and TrustManager at runtime](#support-for-swapping-keymanager-and-trustmanager-at-runtime)\n     - [Trust additional new certificates at runtime](#trust-additional-new-certificates-at-runtime)\n     - [Routing client identity to specific host](#routing-identity-material-to-specific-host)\n     - [Updating client identity routes at runtime](#updating-identity-routes-at-runtime) \n     - [Managing additional identities at runtime](#managing-additional-identities-at-runtime)\n     - [Managing ssl session](#managing-ssl-session)\n     - [Extracting server certificates](#extracting-server-certificates)\n       - [Single server](#single-server)\n       - [Bulk extraction from multiple servers](#bulk-extraction-from-multiple-servers)\n       - [Extracting certificates behind proxy](#extracting-certificates-behind-proxy)\n       - [Extracting certificates behind proxy with authentication](#extracting-certificates-behind-proxy-with-authentication)\n       - [Extracting certificates as pem](#extracting-certificates-as-pem)\n     - [Using P7B or PKCS#7 files](#using-p7b-or-pkcs7-files)\n     - [Using DER files](#using-der-files)\n     - [Using PFX or P12 or PKCS#12 Files](#using-pfx-p12-or-pkcs12-files)\n     - [Using PEM Files](#using-pem-files)\n       - [Loading pem files from the classpath](#loading-pem-files-from-the-classpath)\n       - [Loading pem files from the file system](#loading-pem-files-from-anywhere-on-the-filesystem)\n       - [Loading pem files from InputStream](#loading-pem-files-from-inputstream)\n       - [Loading pem files from string content](#loading-pem-files-from-string-content)\n       - [Loading encrypted pem files](#loading-encrypted-pem-files)\n     - [Migrating from classic configuration](#migrating-from-classic-configuration)\n     - [Global SSL configuration](#global-ssl-configuration)\n     - [Logging certificate validation](#logging-detailed-certificate-validation)\n     - [Logging detailed KeyManager flow, input and output](#logging-detailed-keymanager-flow-input-and-output)\n     - [Fluently mapping SSLFactory](#fluently-mapping-sslfactory)\n   - [Returnable values from the SSLFactory](#returnable-values-from-the-sslfactory)\n3. [Additional mappers for specific libraries](#additional-mappers-for-specific-libraries)\n   - [Netty](#netty)\n   - [Jetty](#jetty)\n   - [Apache](#apache)\n     - [Apache 4](#apache-4)\n     - [Apache 5](#apache-5)\n4. [Tested HTTP Clients](#tested-http-clients)\n5. [Contributing](#contributing)\n6. [Contributors](#contributors-)   \n7. [License](#license)\n\n## Introduction\nAyza is a library which provides a High-Level SSLFactory class for configuring a http client or a server to communicate over SSL/TLS for one way authentication or two-way authentication.\nIt is designed to be as lightweight as possible by having minimized the external dependencies. The core library only depends on the SLF4J logging API.\n\n### History\nAs a Java developer I worked for different kinds of clients. Most of the time the application required to call other microservices within the organization or some other http servers. \nThese requests needed to be secured, and therefore it was required to load the ssl materials into the http client. Each http client may require different input value to enable https requests, and therefore I couldn't just copy-paste my earlier configuration into the new project. \nThe resulting configuration was in my opinion always verbose, not reusable, hard to test and hard to maintain. \n\nAs a developer you also need to know how to properly load your file into your application and consume it as a KeyStore instance. Therefore, you also need to understand how to properly create for example a KeyManager and a TrustManager for you SSLContext. \nAyza is taking the responsibility of creating an instance of SSLContext from the provided arguments, and it will provide you all the ssl materials which are required to configure [40+ different Http Client](#tested-http-clients) for Java, Scala and Kotlin. \nI wanted the library to be as easy as possible to use for all developers to give them a kickstart when configuring their Http Client. So feel free to provide feedback or feature requests. \n\nThe library has been renamed to Ayza in September 2025 as I wanted a shorter name, which is easy to pronounce and to make it easy to remember. Detailed information about the rename can be found here: [Renaming project to Ayza](https://github.com/Hakky54/ayza/discussions/670)\n\nThe library by the way also provides other utilities such as:\n- [CertificateExtractingClient](ayza/src/main/java/nl/altindag/ssl/util/CertificateExtractingClient.java)\n- [CertificateUtils](ayza/src/main/java/nl/altindag/ssl/util/CertificateUtils.java)\n- [HostnameVerifierUtils](ayza/src/main/java/nl/altindag/ssl/util/HostnameVerifierUtils.java)\n- [KeyStoreUtils](ayza/src/main/java/nl/altindag/ssl/util/KeyStoreUtils.java)\n- [KeyManagerUtils](ayza/src/main/java/nl/altindag/ssl/util/KeyManagerUtils.java)\n- [TrustManagerUtils](ayza/src/main/java/nl/altindag/ssl/util/TrustManagerUtils.java)\n- [PemUtils](ayza-for-pem/src/main/java/nl/altindag/ssl/pem/util/PemUtils.java)\n- [ProviderUtils](ayza/src/main/java/nl/altindag/ssl/util/ProviderUtils.java)\n- [SSLContextUtils](ayza/src/main/java/nl/altindag/ssl/util/SSLContextUtils.java)\n- [SSLFactoryUtils](ayza/src/main/java/nl/altindag/ssl/util/SSLFactoryUtils.java)\n- [SSLParametersUtils](ayza/src/main/java/nl/altindag/ssl/util/SSLParametersUtils.java)\n- [SSLSessionUtils](ayza/src/main/java/nl/altindag/ssl/util/SSLSessionUtils.java)\n- [SSLSocketUtils](ayza/src/main/java/nl/altindag/ssl/util/SSLSocketUtils.java)\n\n### Advantages:\n* No need for low-level SSLContext configuration anymore\n* No knowledge needed about SSLContext, TrustManager, TrustManagerFactory, KeyManager, KeyManagerFactory and how to create it.\n* Above classes will all be created with just providing an identity and a trust material\n* Load multiple identities/trustStores/keyManagers/trustManagers\n* Hot reload ssl material without need of restarting/recreating Http Client or Server\n\n### Definitions\n* Identity material: A KeyStore or KeyManager which holds the key pair also known as private and public key\n* Trust material: A KeyStore or TrustManager containing one or more certificates also known as public key. This KeyStore contains a list of trusted certificates\n* One way authentication (also known as one way tls, one way ssl): Https connection where the client validates the certificate of the counter party\n* Two way authentication (also known as two way tls, two way ssl, mutual authentication): Https connection where the client as well as the counter party validates the certificate, also known as mutual authentication\n\n### Compatibility\n\n|    Java     |    Kotlin     | Scala | Android |\n|:-----------:|:-------------:|:-----:|:-------:|\n|     8+      |     1.5+      | 2.11+ |   24+   |\n\n## Usage\n### Basic example configuration\nExample configuration with apache http client, or [click here to view the other client configurations](#tested-http-clients)\n```java\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport nl.altindag.ssl.SSLFactory;\n\npublic class App {\n\n    public static void main(String[] args) throws IOException, JSONException {\n        SSLFactory sslFactory = SSLFactory.builder()\n                .withDefaultTrustMaterial()\n                .build();\n\n        HttpClient httpClient = HttpClients.custom()\n                .setSSLContext(sslFactory.getSslContext())\n                .setSSLHostnameVerifier(sslFactory.getHostnameVerifier())\n                .build();\n\n        HttpGet request = new HttpGet(\"https://api.chucknorris.io/jokes/random\");\n\n        HttpResponse response = httpClient.execute(request);\n        String chuckNorrisJoke = new JSONObject(EntityUtils.toString(response.getEntity())).getString(\"value\");\n\n        System.out.println(String.format(\"Received the following status code: %d\", response.getStatusLine().getStatusCode()));\n        System.out.println(String.format(\"Received the following joke: %s\", chuckNorrisJoke));\n    }\n\n}\n```\nResponse:\n```text\nReceived the following status code: 200\nReceived the following joke: If a black cat crosses your path, you have bad luck. If Chuck Norris crosses your path, it was nice knowing you.\n```\n\n#### Other possible configurations\n##### Loading keystore and truststore from the classpath\n```text\nSSLFactory.builder()\n          .withIdentityMaterial(\"identity.jks\", \"password\".toCharArray())\n          .withTrustMaterial(\"truststore.jks\", \"password\".toCharArray())\n          .build();\n```\n\n##### Loading keystore and trust store from anywhere on the filesystem\n```text\nSSLFactory.builder()\n          .withIdentityMaterial(Paths.get(\"/path/to/your/identity.jks\"), \"password\".toCharArray())\n          .withTrustMaterial(Paths.get(\"/path/to/your/truststore.jks\"), \"password\".toCharArray())\n          .build();\n```\n\n##### Loading keystore and trust store from InputStream\n```text\nInputStream keyStoreStream = ...\nInputStream trustStoreStream = ...\n\nSSLFactory.builder()\n          .withIdentityMaterial(keyStoreStream, \"password\".toCharArray())\n          .withTrustMaterial(trustStoreStream, \"password\".toCharArray())\n          .build();\n```\n\n##### Loading trust material with OCSP options\n##### Loading trust material with TrustStore and OCSP options from the classpath\n```text\nCertPathBuilder certPathBuilder = CertPathBuilder.getInstance(\"PKIX\");\nPKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();\nrevocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.NO_FALLBACK));\n\nSSLFactory sslFactory = SSLFactory.builder()\n        .withTrustMaterial(\"truststore.jks\", \"password\".toCharArray(), trustStore -\u003e {\n            PKIXBuilderParameters pkixBuilderParameters = new PKIXBuilderParameters(trustStore, new X509CertSelector());\n            pkixBuilderParameters.addCertPathChecker(revocationChecker);\n            return new CertPathTrustManagerParameters(pkixBuilderParameters);\n        })\n        .build();\n```\n##### Loading trust material with TrustStore and OCSP options from the file system\n```text\nCertPathBuilder certPathBuilder = CertPathBuilder.getInstance(\"PKIX\");\nPKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();\nrevocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.NO_FALLBACK));\n\nSSLFactory sslFactory = SSLFactory.builder()\n        .withTrustMaterial(Paths.get(\"/path/to/your/truststore.jks\"), \"password\".toCharArray(), trustStore -\u003e {\n            PKIXBuilderParameters pkixBuilderParameters = new PKIXBuilderParameters(trustStore, new X509CertSelector());\n            pkixBuilderParameters.addCertPathChecker(revocationChecker);\n            return new CertPathTrustManagerParameters(pkixBuilderParameters);\n        })\n        .build();\n```\n##### Loading trust material with TrustManager and OCSP options\n```text\nX509ExtendedTrustManager trustManager = ...\n\nCertPathBuilder certPathBuilder = CertPathBuilder.getInstance(\"PKIX\");\nPKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();\nrevocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.NO_FALLBACK));\n\nSSLFactory sslFactory = SSLFactory.builder()\n        .withTrustMaterial(trustManager, trustStore -\u003e {\n            PKIXBuilderParameters pkixBuilderParameters = new PKIXBuilderParameters(trustStore, new X509CertSelector());\n            pkixBuilderParameters.addCertPathChecker(revocationChecker);\n            return new CertPathTrustManagerParameters(pkixBuilderParameters);\n        })\n        .build();\n```\n\n##### Loading trust material with certificates and OCSP options\n```text\nList\u003cCertificate\u003e certificates = ...\n\nCertPathBuilder certPathBuilder = CertPathBuilder.getInstance(\"PKIX\");\nPKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();\nrevocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.NO_FALLBACK));\n\nSSLFactory sslFactory = SSLFactory.builder()\n        .withTrustMaterial(certificates, trustStore -\u003e {\n            PKIXBuilderParameters pkixBuilderParameters = new PKIXBuilderParameters(trustStore, new X509CertSelector());\n            pkixBuilderParameters.addCertPathChecker(revocationChecker);\n            return new CertPathTrustManagerParameters(pkixBuilderParameters);\n        })\n        .build();\n```\n\n##### Enhanceable trust validations\nBy default, the TrustManager ships with default validations to validate if the counterparty is trusted during the SSL Handshake. \nIf needed the default behaviour can be overruled by custom validators.\nIf a custom validator is specified and if the condition evaluates to true, then the certificate of the counterparty will be trusted. If the condition evaluates to false, than it will fall back to the default behaviour of the TrustManager.\n```text\nSSLFactory.builder()\n          .withDefaultTrustMaterial()\n          .withTrustEnhancer(trustManagerParameters -\u003e {\n              X509Certificate[] chain = trustManagerParameters.getChain();\n              return chain[0].getIssuerX500Principal().getName().equals(\"Foo\")\n                      \u0026\u0026 chain[0].getSubjectX500Principal().getName().equals(\"Bar\");\n          })\n          .build();\n```\n##### Hide trusted certificate names of a server\nBy default, a server exposes the list of trusted certificate names if requested by the client. The list of trusted certificate names can be requested with:\n```shell\nopenssl s_client -showcerts -servername 127.0.0.1 -connect 127.0.0.1:8443\n```\n\nThe output will be under `Acceptable client certificate CA names`:\n![alt text](https://github.com/Hakky54/ayza/blob/master/images/demo-sending-server-ca-names.png?raw=true)\n\nFor some end-user this might lead into information leaks and security risks. This information can be hidden away so the client cannot request it anymore with an additional option within the `SSLFactory#withConcealedTrustMaterial()`. An example usage would be:\n```text\nSSLFactory updatedSslFactory = SSLFactory.builder()\n      .withIdentityMaterial(Paths.get(\"/path/to/your/identity.jks\"), \"password\".toCharArray())\n      .withTrustMaterial(Paths.get(\"/path/to/your/truststore.jks\"), \"password\".toCharArray())\n      .withConcealedTrustMaterial()\n      .build();\n```\n\nWhich will result into the following output:\n![alt text](https://github.com/Hakky54/ayza/blob/master/images/demo-not-sending-server-ca-names.png?raw=true)\n\n##### Trusting all certificates without validation, not recommended to use at production!\n```text\nSSLFactory.builder()\n          .withUnsafeTrustMaterial()\n          .build();\n```\n\n##### Skip hostname validation\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n          .withDefaultTrustMaterial()\n          .withUnsafeHostnameVerifier()\n          .build();\n\nHttpsURLConnection.setDefaultHostnameVerifier(sslFactory.getHostnameVerifier());\nSystem.setProperty(\"jdk.internal.httpclient.disableHostnameVerification\", Boolean.TRUE.toString());\n```\n\n##### Loading JDK and OS trusted certificates\n```text\nSSLFactory.builder()\n          .withDefaultTrustMaterial()\n          .withSystemTrustMaterial()\n          .build();\n```\n\n##### Using specific protocols, ciphers with custom secure random and hostname verifier\nIf you are using java 11 or newer, than you are also able to use TLSv1.3 as encryption protocol by default.\n```text\nSSLFactory.builder()\n          .withDefaultTrustMaterial()\n          .withProtocols(\"TLSv1.3\", \"TLSv1.2\")\n          .withCiphers(\"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384\")\n          .withHostnameVerifier(hostnameVerifier)\n          .withSecureRandom(secureRandom)\n          .build();\n```\n\n### Enhanceable hostname verifier\nIf you want to improve or whitelist certain hostnames from the default hostname verifier, you can apply the snippet bellow. If the method body returns true the hostname will be trusted by default\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n          .withDefaultTrustMaterial()\n          .withHostnameVerifierEnhancer(parameters -\u003e \"localhost\".equals(parameters.getHostname()))\n          .build();\n```\n\n##### Support for using multiple identity materials and trust materials\n```text\nSSLFactory.builder()\n          .withIdentityMaterial(\"identity-1.jks\", password)\n          .withIdentityMaterial(\"identity-2.jks\", password)\n          .withIdentityMaterial(\"identity-3.jks\", password)\n          .withIdentityMaterial(\"identity-4.jks\", password)\n          .withTrustMaterial(\"truststore-1.jks\", password)\n          .withTrustMaterial(\"truststore-2.jks\", password)\n          .withTrustMaterial(\"truststore-3.jks\", password)\n          .withTrustMaterial(\"truststore-4.jks\", password)\n          .build();\n```\nIn some use cases multiple identities can fail to work. If that happens please try to add the additional SSLFactory option of identity route. See here for more: [Routing identity to specific host](#routing-identity-material-to-specific-host)\n\n##### Support for using X509ExtendedKeyManager and X509ExtendedTrustManager\n```text\nX509ExtendedKeyManager keyManager = ...\nX509ExtendedTrustManager trustManager = ...\n\nSSLFactory.builder()\n          .withIdentityMaterial(keyManager)\n          .withTrustMaterial(trustManager)\n          .build();\n```\n\n##### Using dummy identity and trust material\nIn some use cases it may be useful to use a dummy identity or trust material. An example use case would be to create a base SSLFactory with the dummies which can be swapped afterwords. See below for a refactored version of [Support for swapping KeyManager and TrustManager at runtime](#support-for-swapping-keymanager-and-trustmanager-at-runtime).\n```text\nSSLFactory baseSslFactory = SSLFactory.builder()\n          .withDummyIdentityMaterial()\n          .withDummyTrustMaterial()\n          .withSwappableIdentityMaterial()\n          .withSwappableTrustMaterial()\n          .build();\n          \nHttpClient httpClient = HttpClient.newBuilder()\n          .sslParameters(sslFactory.getSslParameters())\n          .sslContext(sslFactory.getSslContext())\n          .build()\n          \nRunnable sslUpdater = () -\u003e {\n    SSLFactory updatedSslFactory = SSLFactory.builder()\n          .withIdentityMaterial(Paths.get(\"/path/to/your/identity.jks\"), \"password\".toCharArray())\n          .withTrustMaterial(Paths.get(\"/path/to/your/truststore.jks\"), \"password\".toCharArray())\n          .build();\n    \n    SSLFactoryUtils.reload(baseSslFactory, updatedSslFactory);\n};\n\n// initial update of ssl material to replace the dummies\nsslUpdater.run();\n   \n// update ssl material every hour    \nExecutors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(sslUpdater, 1, 1, TimeUnit.HOURS);\n\nHttpResponse\u003cString\u003e response = httpClient.send(aRequest, HttpResponse.BodyHandlers.ofString());\n```\n##### Support for using a single KeyStore which contains multiple keys with different passwords\n```text\nKeyStore keyStore = ...\nX509ExtendedKeyManager keyManager = KeyManagerUtils.createKeyManager(keyStore, Map.of(\n        \"foo\",\"foo-password\".toCharArray(),\n        \"bar\",\"bar-password\".toCharArray(),\n        \"lorum-ipsum\",\"lorum-ipsum-password\".toCharArray()\n));\n\nSSLFactory.builder()\n          .withIdentityMaterial(keyManager)\n          .withDefaultTrustMaterial()\n          .build();\n```\n##### Support for using PrivateKey and Certificates\n```text\nPrivateKey privateKey = ...\nchar[] privateKeyPassword = ...\nCertificate[] certificateChain = ...\n\nCertificate trustedCertificate = ...\n\nSSLFactory.builder()\n          .withIdentityMaterial(privateKey, privateKeyPassword, certificateChain)\n          .withTrustMaterial(trustedCertificate)\n          .build();\n```\n##### Support for reloading ssl at runtime\n###### Reload identity and trust material\nIt is possible to reload or update the ssl configuration while already using it with your client or server without the need of restarting your application or recreating it with SSLFactory. The identity and trust material may expire at some point in time and needs to be replaced to be still functional.\nRestart of the application with a traditional setup is unavoidable and can result into a downtime for x amount of time. A restart is not needed when using the setup below. The below example is a high-level method of reloading the ssl configuration, if you prefer to use a low-level setup please have a look at the following example displayed here: [Hot swap KeyManager and TrustManager at runtime](#support-for-swapping-keymanager-and-trustmanager-at-runtime).\n```text\nSSLFactory baseSslFactory = SSLFactory.builder()\n          .withDummyIdentityMaterial()\n          .withDummyTrustMaterial()\n          .withSwappableIdentityMaterial()\n          .withSwappableTrustMaterial()\n          .build();\n          \nHttpClient httpClient = HttpClient.newBuilder()\n          .sslParameters(sslFactory.getSslParameters())\n          .sslContext(sslFactory.getSslContext())\n          .build()\n          \nRunnable sslUpdater = () -\u003e {\n    SSLFactory updatedSslFactory = SSLFactory.builder()\n          .withIdentityMaterial(Paths.get(\"/path/to/your/identity.jks\"), \"password\".toCharArray())\n          .withTrustMaterial(Paths.get(\"/path/to/your/truststore.jks\"), \"password\".toCharArray())\n          .build();\n    \n    SSLFactoryUtils.reload(baseSslFactory, updatedSslFactory);\n};\n\n// initial update of ssl material to replace the dummies\nsslUpdater.run();\n   \n// update ssl material every hour    \nExecutors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(sslUpdater, 1, 1, TimeUnit.HOURS);\n\nHttpResponse\u003cString\u003e response = httpClient.send(aRequest, HttpResponse.BodyHandlers.ofString());\n```\nSee here for a basic reference implementation for a server: [GitHub - Instant SSL Reloading](https://github.com/Hakky54/java-tutorials/tree/main/instant-server-ssl-reloading)\nThe code example above cleans the cache instantly which forces any client or server to create a new ssl session and so it requires a new ssl handshake. If you prefer to use existing ssl session for existing connection, but want to use a new ssl session for new clients or servers, then you can use the following snippet below. \nIn that way existing connections which already have done the ssl handshake won't require to do another handshake till the ssl session expires with the default timeout. \n```text\nSSLFactoryUtils.reload(baseSslFactory, updatedSslFactory, false);\n```\n\nSee also here for other examples:\n- [Instant Server SSL Reloading with Spring Boot and Jetty](https://github.com/Hakky54/java-tutorials/tree/main/instant-server-ssl-reloading)\n- [Instant Server SSL Reloading with Spring Boot and Tomcat](https://github.com/Hakky54/java-tutorials/tree/main/instant-ssl-reloading-with-spring-tomcat)\n- [Instant Server SSL Reloading with Vert.x](https://github.com/Hakky54/java-tutorials/tree/main/instant-server-ssl-reloading-with-vertx/vertx-server)\n- [Instant Server SSL Reloading with Netty](https://github.com/Hakky54/java-tutorials/tree/main/instant-server-ssl-reloading-with-netty/netty-server)\n- [Instant Server SSL Reloading with gRPC](https://github.com/Hakky54/java-tutorials/tree/main/grpc-client-server-with-ssl/instant-server-ssl-reloading-with-grpc)\n- [Instant Server SSL Reloading with Spring Boot and Jetty and Database](https://github.com/Hakky54/java-tutorials/tree/main/instant-ssl-reloading-with-spring-jetty-database)\n- [Instant Server SSL Reloading with Quarkus](https://github.com/Hakky54/java-tutorials/tree/main/instant-server-ssl-reloading-with-quarkus)\n\n###### Reload ssl parameters\nAdditionally the SSL parameters can also be reloaded such as ciphers. A basic example is demonstrated below:\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n          .withIdentityMaterial(Paths.get(\"/path/to/your/identity.jks\"), \"password\".toCharArray())\n          .withTrustMaterial(Paths.get(\"/path/to/your/truststore.jks\"), \"password\".toCharArray())\n          .withSwappableSslParameters()\n          .build();\n          \nsslFactory.getSslParameters().setCipherSuites(new String[]{\"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256\"})\n```\nPlease note that this might not work for all http clients and servers. It works out of the box with Jetty, but for Netty it needs some additional configuration see the code snippet below. It basically depends on how the http client or server uses the ciphers or other ssl properties during the ssl handshake.\nPlease be aware that this option has some limitations/drawbacks. It might cause other options of a server not to work, so it is advised to test this option in dept. If it breaks your server configuration such as ALPN I would not recommend to use reloadable ssl parameters. Updating your server properties and running a rolling update/restarting your server would be a better option.\n\nThe option below might be needed for some servers/clients to reload ssl parameters, for example Netty Server.\n```text\nSSLFactory sslFactory = ... // your initialized SSLFactory similar to the above one with SwappableSslParameters \nProvider provider = ProviderUtils.create(sslFactory);\nSecurity.insertProviderAt(provider, 1);\n\n// Initialize your server at this point\n```\n\n##### Support for swapping KeyManager and TrustManager at runtime\nIt is possible to swap a KeyManager and TrustManager from a SSLContext, SSLSocketFactory and SSLServerSocketFactory while already using it within your client or server at runtime. This option will enable to refresh the identity and trust material of a server or client without the need of restarting your application or recreating it with SSLFactory. The identity and trust material may expire at some point in time and needs to be replaced to be still functional.\nRestart of the application with a traditional setup is unavoidable and can result into a downtime for x amount of time. A restart is not needed when using the setup below.\n```text\nSSLFactory baseSslFactory = SSLFactory.builder()\n          .withIdentityMaterial(Paths.get(\"/path/to/your/identity.jks\"), \"password\".toCharArray())\n          .withTrustMaterial(Paths.get(\"/path/to/your/truststore.jks\"), \"password\".toCharArray())\n          .withSwappableIdentityMaterial()\n          .withSwappableTrustMaterial()\n          .build();\n          \nHttpClient httpClient = HttpClient.newBuilder()\n          .sslParameters(sslFactory.getSslParameters())\n          .sslContext(sslFactory.getSslContext())\n          .build()\n\n// execute https request\nHttpResponse\u003cString\u003e response = httpClient.send(aRequest, HttpResponse.BodyHandlers.ofString());\n\nSSLFactory updatedSslFactory = SSLFactory.builder()\n          .withIdentityMaterial(Paths.get(\"/path/to/your/identity.jks\"), \"password\".toCharArray())\n          .withTrustMaterial(Paths.get(\"/path/to/your/truststore.jks\"), \"password\".toCharArray())\n          .build();\n          \n// swap identity and trust materials and reuse existing http client\nKeyManagerUtils.swapKeyManager(baseSslFactory.getKeyManager().get(), updatedSslFactory.getKeyManager().get());\nTrustManagerUtils.swapTrustManager(baseSslFactory.getTrustManager().get(), updatedSslFactory.getTrustManager().get());\n\n// Cleanup old ssl sessions by invalidating them all. Forces to use new ssl sessions which will be created by the swapped KeyManager/TrustManager\nSSLSessionUtils.invalidateCaches(baseSslFactory.getSslContext());\n\nHttpResponse\u003cString\u003e response = httpClient.send(aRequest, HttpResponse.BodyHandlers.ofString());\n```\n\nSee here for a basic reference implementation for a\nserver: [GitHub - Instant SSL Reloading](https://github.com/Hakky54/java-tutorials/tree/main/instant-server-ssl-reloading)\n\n##### Trust additional new certificates at runtime\n\nAlthough it is possible to reload the complete trust material as shown before\nin [Reloading SSL at runtime](#support-for-reloading-ssl-at-runtime)\nand [Hot swap KeyManager and TrustManager at runtime](#support-for-swapping-keymanager-and-trustmanager-at-runtime), in\nsome occasions you might want the trust additional new certificates without reloading all the trust material as it\nmight be redundant. Especially if you want to keep other trust material intact which is already loaded to your\nSSLFactory and you don't want it to be reloaded. An example use case would be using the JDK and OS trusted Certificates\nAuthorities\nand your custom truststore which can grow over time. See below for two examples:\n\n##### Option 1\n\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n        .withDefaultTrustMaterial()\n        .withSystemTrustMaterial()\n        .withInflatableTrustMaterial()\n        .build();\n\nList\u003cX509Certificate\u003e certificates = ... ; // after some point in time you have a couple of new CA which you want to trust\n\nTrustManagerUtils.addCertificate(sslFactory.getTrustManager().get(), certificates);\n```\n\nWith the option below your newly trusted certificates will be also stored on the file-system.\nIf the file exists then it will first read and append to it. The predicate is thread-safe and can be used for example\nprompting the user to trust the certificate if integrated in a GUI.\n\n##### Option 2\n\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n        .withDefaultTrustMaterial()\n        .withSystemTrustMaterial()\n        .withInflatableTrustMaterial(Paths.get(\"/path/to/truststore.p12\"), \"password\".toCharArray(), \"PKCS12\", trustManagerParameters -\u003e {\n            // do some validation to decide whether to trust this certificate\n            return true;\n        })\n        .build();\n```\n\nA proof-of-concept is available here: [GitHub - Trust Me](https://github.com/Hakky54/trust-me) which demonstrates how it can be integrated in a GUI and prompting the end-user to either trust or reject the server certificate. It will be applied instantly and the ssl configuration will be reloaded.\n\n##### Routing identity material to specific host\n\nIt may occur that the client is sending the wrong certificate to the server when using multiple identities. This will\nhappen when the client certificate has insufficient information for the underlying ssl engine (the KeyManager) and\ntherefore it cannot select the right certificate.\nRecreating the certificates can resolve this issue. However, if that is not possible you can provide an option to the\nengine to use a specific certificate for a given server. Below is an example setup for correctly routing the client\nidentity based on the alias which can be found within the KeyStore file.\n\n```text\nSSLFactory.builder()\n          .withIdentityMaterial(\"identity-1.jks\", password)\n          .withIdentityMaterial(\"identity-2.jks\", password)\n          .withTrustMaterial(\"truststore.jks\", password)\n          .withIdentityRoute(\"client-alias-one\", \"https://localhost:8443/\", \"https://localhost:8453/\")\n          .withIdentityRoute(\"client-alias-two\", \"https://localhost:8463/\", \"https://localhost:8473/\")\n          .build();\n```\n##### Updating identity routes at runtime\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n          .withIdentityMaterial(\"identity-1.jks\", password)\n          .withIdentityMaterial(\"identity-2.jks\", password)\n          .withTrustMaterial(\"truststore.jks\", password)\n          .withIdentityRoute(\"client-alias-one\", \"https://localhost:8443/\", \"https://localhost:8453/\")\n          .withIdentityRoute(\"client-alias-two\", \"https://localhost:8463/\", \"https://localhost:8473/\")\n          .build();\n\nX509ExtendedKeyManager keyManager = sslFactory.getKeyManager().get()\n\n// Add additional routes next to the existing ones\nKeyManagerUtils.addIdentityRoute(keyManager, \"client-alias-one\", \"https://localhost:8463/\", \"https://localhost:8473/\")\n\n// Override existing routes\nKeyManagerUtils.overrideIdentityRoute(keyManager, \"client-alias-two\", \"https://localhost:9463/\", \"https://localhost:9473/\")\n```\n##### Managing additional identities at runtime\nPlease beware when using multiple identities from a keystore. The alias name from the key entry within the keystore should be unique across all the identities.\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n          .withInflatableIdentityMaterial()\n          .withIdentityMaterial(Paths.get(\"/path/to/your/identity-1.jks\"), \"password\".toCharArray())\n          .withTrustMaterial(\"truststore.jks\", password)\n          .withIdentityRoute(\"client-alias-one\", \"https://localhost:8443/\", \"https://localhost:8453/\")\n          .build();\n          \nX509ExtendedKeyManager keyManager = sslFactory.getKeyManager().get();\n\n// Adding identity and an additional route\nKeyStore identityTwo = KeyStoreUtils.loadKeyStore(Paths.get(\"/path/to/your/identity-2.jks\"), \"password\".toCharArray());\nKeyManagerUtils.addIdentityMaterial(keyManager, \"client-alias-two\", identityTwo, \"password\".toCharArray());\nKeyManagerUtils.addIdentityRoute(keyManager, \"client-alias-two\", \"https://localhost:8463/\", \"https://localhost:8473/\");\n\n// Getting existing list of aliases from the inflatable key manager\nList\u003cString\u003e aliases = KeyManagerUtils.getAliases(keyManager);\n\n// Removing identity\nKeyManagerUtils.removeIdentityMaterial(keyManager, \"client-alias-two\");\nKeyManagerUtils.removeIdentityRoute(keyManager, \"client-alias-two\");\n```\n##### Managing ssl session\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n          .withIdentityMaterial(\"identity.jks\", \"password\".toCharArray())\n          .withTrustMaterial(\"truststore.jks\", \"password\".toCharArray())\n          .withSessionTimeout(3600) // Amount of seconds until it will be invalidated\n          .withSessionCacheSize(1024) // Amount of bytes until it will be invalidated\n          .build();\n          \nSSLContext sslContext = sslFactory.getSslContext();\n          \n// Caches can be invalidated with the snippet below\nSSLSessionUtils.invalidateCaches(sslContext);\n\n// or any other option:\nSSLSessionUtils.invalidateCachesBefore(\n        sslContext,\n        ZonedDateTime.of(LocalDateTime.of(2021, JANUARY, 1, 15, 55), ZoneOffset.UTC)\n);\n\nSSLSessionUtils.invalidateCachesAfter(\n        sslContext,\n        ZonedDateTime.of(LocalDateTime.of(2021, FEBRUARY, 10, 8, 14), ZoneOffset.UTC)\n);\n\nSSLSessionUtils.invalidateCachesBetween(\n        sslContext,\n        ZonedDateTime.now().minusHours(2),    // from\n        ZonedDateTime.now()                   // up till\n);\n```\n##### Extracting server certificates\n###### Single server\n```text\nList\u003cX509Certificate\u003e certificates = CertificateUtils.getCertificatesFromExternalSource(\"https://github.com/\");\n```\n\n###### Bulk extraction from multiple servers\n```text\nMap\u003cString, List\u003cX509Certificate\u003e\u003e certificates = CertificateUtils.getCertificatesFromExternalSources(\n            \"https://github.com/\", \n            \"https://stackoverflow.com/\", \n            \"https://www.reddit.com/\",\n            \"https://www.youtube.com/\");\n```\n\n###### Extracting certificates behind proxy\n```text\nProxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"my-custom-host\", 1234));\nList\u003cX509Certificate\u003e certificates = CertificateUtils.getCertificatesFromExternalSource(proxy, \"https://github.com/\");\n```\n\n###### Extracting certificates behind proxy with authentication\n```text\nProxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"my-custom-host\", 1234));\nPasswordAuthentication passwordAuthentication = new PasswordAuthentication(\"foo\", \"bar\".toCharArray());\nList\u003cX509Certificate\u003e certificates = CertificateUtils.getCertificatesFromExternalSource(proxy, passwordAuthentication, \"https://github.com/\");\n```\n\n###### Extracting certificates as pem\nAll previous examples are also available for extracting the server certificates as pem. The method has an additional `asPem` suffix. See below for all of the examples:\n```text\n// single\nList\u003cString\u003e certificates = CertificateUtils.getCertificatesFromExternalSourceAsPem(\"https://github.com/\");\n\n// bulk\nMap\u003cString, List\u003cX509Certificate\u003e\u003e urlsToCertificates = CertificateUtils.getCertificatesFromExternalSourcesAsPem(\n            \"https://github.com/\", \n            \"https://stackoverflow.com/\", \n            \"https://www.reddit.com/\",\n            \"https://www.youtube.com/\");\n    \n// proxy        \nProxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"my-custom-host\", 1234));\ncertificates = CertificateUtils.getCertificatesFromExternalSource(proxy, \"https://github.com/\");\n\n// proxy + authentication\nPasswordAuthentication passwordAuthentication = new PasswordAuthentication(\"foo\", \"bar\".toCharArray());\ncertificates = CertificateUtils.getCertificatesFromExternalSource(proxy, passwordAuthentication, \"https://github.com/\");\n```\n\nSee here also for a demo application for the CLI: [GitHub - Certificate Ripper](https://github.com/Hakky54/certificate-ripper)\n\n#### Using P7B or PKCS#7 Files\nSupport for using p7b formatted certificates and certificate-chain from classpath, any directory or as an InputStream. \nP7b file is a text file containing a `-----BEGIN PKCS7-----` as header, `-----END PKCS7-----` as footer and has a Base64 encoded data between it.\n```\nList\u003cCertificate\u003e certificates = CertificateUtils.loadCertificate(\"certificate.p7b\");\n\nSSLFactory.builder()\n          .withTrustMaterial(certificates)\n          .build();\n```\n\n#### Using DER Files\nSupport for using der formatted certificates and certificate-chain from classpath, any directory or as an InputStream.\nDer file is a binary form of a certificate. Commonly used extensions are `.cer` and `crt`.\n```\nList\u003cCertificate\u003e certificates = CertificateUtils.loadCertificate(\"certificate.cer\");\n\nSSLFactory.builder()\n          .withTrustMaterial(certificates)\n          .build();\n```\n\n#### Using PFX, P12 or PKCS#12 Files\nPFX and p12 are both PKCS#12 type keystores which are supported.\n\n```text\nSSLFactory.builder()\n          .withIdentityMaterial(\"identity.p12\", \"password\".toCharArray())\n          .withTrustMaterial(\"truststore.p12\", \"password\".toCharArray())\n          .build();\n```\n\n#### Using PEM Files\n\nSupport for using pem formatted private key and certificates from classpath, any directory or as an InputStream.\nSee [PemUtilsShould](ayza-for-pem/src/test/java/nl/altindag/ssl/pem/util/PemUtilsShould.java) for\ndetailed usages.\nAdd the dependency below to use this feature, it also includes the core features from the library such as SSLFactory.\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.hakky54\u003c/groupId\u003e\n  \u003cartifactId\u003eayza-for-pem\u003c/artifactId\u003e\n  \u003cversion\u003e10.0.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n##### Loading pem files from the classpath\n```\nX509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial(\"certificate.pem\", \"private-key.pem\");\nX509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial(\"some-trusted-certificate.pem\");\n\nSSLFactory.builder()\n          .withIdentityMaterial(keyManager)\n          .withTrustMaterial(trustManager)\n          .build();\n```\n##### Loading pem files from anywhere on the filesystem\n```\nX509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial(Paths.get(\"/path/to/your/certificate.pem\"), Paths.get(\"/path/to/your/private-key.pem\"));\nX509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial(Paths.get(\"/path/to/your/some-trusted-certificate.pem\"));\n```\n##### Loading pem files from InputStream\n```\nInputStream privateKey = ...\nInputStream certificate = ...\nInputStream trustedCertificates = ...\n\nX509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial(certificate, privateKey);\nX509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial(trustedCertificates);\n```\n##### Loading pem files from string content\n```\nString privateKey =\n        \"-----BEGIN ENCRYPTED PRIVATE KEY-----\\n\" +\n        \"MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIy3Fposf+2ccCAggA\\n\" +\n        \"-----END ENCRYPTED PRIVATE KEY-----\\n\";\n\nString certificate =\n        \"-----BEGIN CERTIFICATE-----\\n\" +\n        \"g0Y2YBH5v0xmi8sYU7weOcwynkjZARpUltBUQ0pWCF5uJsEB8uE8PPDD3c4=\\n\" +\n        \"-----END CERTIFICATE-----\\n\";\n\nString trustedCertificates =\n        \"-----BEGIN CERTIFICATE-----\\n\" +\n        \"CC01zojqS10nGowxzOiqyB4m6wytmzf0QwjpMw==\\n\" +\n        \"-----END CERTIFICATE-----\\n\";\n\nX509ExtendedKeyManager keyManager = PemUtils.parseIdentityMaterial(certificate, privateKey, \"secret\".toCharArray());\nX509ExtendedTrustManager trustManager = PemUtils.parseTrustMaterial(trustedCertificates);\n```\n##### Loading encrypted pem files\n```\nX509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial(\"certificate.pem\", \"private-key.pem\", \"secret\".toCharArray());\n```\n##### Migrating from classic configuration\nBelow is an example of the classic configuration for enabling ssl for your application.\n```\n-Djavax.net.ssl.trustStore=/path/to/truststore.jks\n-Djavax.net.ssl.trustStoreType=jks\n-Djavax.net.ssl.trustStorePassword=changeit\n-Djavax.net.ssl.trustStoreProvider=SunJSSE\n\n-Djavax.net.ssl.keyStore=/path/to/keystore.jks\n-Djavax.net.ssl.keyStoreType=jks\n-Djavax.net.ssl.keyStorePassword=changeit\n-Djavax.net.ssl.keyStoreProvider=SunJSSE\n\n-Dhttps.protocols=TLSv1.3\n-Dhttps.cipherSuites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\n```\n\nSSLFactory can be used with these properties together with the existing properties with the following snippet:\n```\nSSLFactory sslFactory = SSLFactory.builder()\n        .withSystemPropertyDerivedIdentityMaterial()\n        .withSystemPropertyDerivedTrustMaterial()\n        .withSystemPropertyDerivedProtocols()\n        .withSystemPropertyDerivedCiphers()\n        .build();\n\nSSLContext.setDefault(sslFactory.getSslContext());\n```\n\nThe SSLFactory returnable values can be supplied to the http client as shown [here](#tested-http-clients)\n\n##### Global SSL configuration\nIf it is not possible to adjust the ssl configuration of a server or client because it is using the default ssl configuration or using a pre-configured, then you can give the snippet below a try.\nThe snippet below will ensure the default SSLContext will be the one which is constructed by SSLFactory and the Security utility of Java will also use the SSLContext of SSLFactory if it is initialized with `SSLContext.getInstance(\"TLS\")` or any of the following protocols: SSL, SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3\nSee also a working demo here: [Bypassing and overruling SSL configuration of libraries](https://github.com/Hakky54/java-tutorials/tree/main/bypassing-overruling-ssl-configuration)\n```\n// The SSLFactory below is just an example, use your own custom initialized one here\nSSLFactory sslFactory = SSLFactory.builder()\n        .withDefaultTrustMaterial()\n        .withSystemTrustMaterial()\n        .build();\n\nProvider provider = ProviderUtils.create(sslFactory);\nSecurity.insertProviderAt(provider, 1);\nSSLContext.setDefault(sslFactory.getSslContext());\n```\n\n##### Logging detailed certificate validation\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n        .withTrustMaterial(Paths.get(\"/path/to/your/truststore.jks\"), \"password\".toCharArray())\n        .withLoggingTrustMaterial()\n        .build();\n        \n// run your server or client and analyse the logs\n```\n\nYou will get a log message which is similar to the following one:\n```text\nValidating the certificate chain of the server[google.com:443] with authentication type RSA, while also using the SSLEngine. See below for the full chain of the server:\n[[\n[\n  Version: V3\n  Subject: CN=*.google.com, O=Google LLC, L=Mountain View, ST=California, C=US\n  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11\n\n  Key:  Sun EC public key, 256 bits\n  public x coord: 54347275970077566368513898626765286548687250565786921039060191273785455056345\n  public y coord: 88043846562958291988419087726639688241289668084120802006631053348150453315748\n  parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)\n  Validity: [From: Wed Oct 16 14:36:57 CEST 2019,\n               To: Wed Jan 08 13:36:57 CET 2020]\n  Issuer: CN=GTS CA 1O1, O=Google Trust Services, C=US\n  SerialNumber: [    a2b1428b 94a636b2 08000000 0019fa68]\n\nCertificate Extensions: 10\n[1]: ObjectId: 1.3.6.1.4.1.11129.2.4.2 Criticality=false\nExtension unknown: DER encoded OCTET string =\n0000: 04 81 F5 04 81 F2 00 F0   00 76 00 B2 1E 05 CC 8B  .........v......\n0010: A2 CD 8A 20 4E 87 66 F9   2B B9 8A 25 20 67 6B DA  ... N.f.+..% gk.\n0020: FA 70 E7 B2 49 53 2D EF   8B 90 5E 00 00 01 6D D4  .p..IS-...^...m.\n0030: C9 39 F6 00 00 04 03 00   47 30 45 02 20 3B E9 89  .9......G0E. ;..\n0040: 83 7B 8C F6 11 AC C5 2C   2E 8C 21 E9 DE 24 3F E2  .......,..!..$?.\n0050: 3B 46 6C 20 86 36 38 A3   E2 39 89 80 13 02 21 00  ;Fl .68..9....!.\n0060: C0 B8 0E AC C3 71 A9 66   B3 49 AE 46 2F FF CE 35  .....q.f.I.F/..5\n0070: CE C0 CD 5B 3E AA 3B 33   1B CC A4 7E E2 62 98 78  ...[\u003e.;3.....b.x\n0080: 00 76 00 5E A7 73 F9 DF   56 C0 E7 B5 36 48 7D D0  .v.^.s..V...6H..\n0090: 49 E0 32 7A 91 9A 0C 84   A1 12 12 84 18 75 96 81  I.2z.........u..\n00A0: 71 45 58 00 00 01 6D D4   C9 39 99 00 00 04 03 00  qEX...m..9......\n00B0: 47 30 45 02 20 1B 76 BF   FD 79 76 D9 A0 A1 6D F7  G0E. .v..yv...m.\n00C0: F2 33 67 55 DD 38 7A F5   98 E0 28 05 25 DD 3D 8B  .3gU.8z...(.%.=.\n00D0: A5 91 BC DF 2E 02 21 00   87 81 AD 92 A6 1D 6B A0  ......!.......k.\n00E0: 32 75 B8 68 FF 5C D2 F6   FA 11 0E FF 44 2D 7D DB  2u.h.\\......D-..\n00F0: 9C 1A 27 3A D3 32 CB B7                            ..':.2..\n\n\n[2]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false\nAuthorityInfoAccess [\n  [\n   accessMethod: ocsp\n   accessLocation: URIName: http://ocsp.pki.goog/gts1o1\n, \n   accessMethod: caIssuers\n   accessLocation: URIName: http://pki.goog/gsr2/GTS1O1.crt\n]\n]\n\n[3]: ObjectId: 2.5.29.35 Criticality=false\nAuthorityKeyIdentifier [\nKeyIdentifier [\n0000: 98 D1 F8 6E 10 EB CF 9B   EC 60 9F 18 90 1B A0 EB  ...n.....`......\n0010: 7D 09 FD 2B                                        ...+\n]\n]\n\n[4]: ObjectId: 2.5.29.19 Criticality=true\nBasicConstraints:[\n  CA:false\n  PathLen: undefined\n]\n\n[5]: ObjectId: 2.5.29.31 Criticality=false\nCRLDistributionPoints [\n  [DistributionPoint:\n     [URIName: http://crl.pki.goog/GTS1O1.crl]\n]]\n\n[6]: ObjectId: 2.5.29.32 Criticality=false\nCertificatePolicies [\n  [CertificatePolicyId: [2.23.140.1.2.2]\n[]  ]\n  [CertificatePolicyId: [1.3.6.1.4.1.11129.2.5.3]\n[]  ]\n]\n\n[7]: ObjectId: 2.5.29.37 Criticality=false\nExtendedKeyUsages [\n  serverAuth\n]\n\n[8]: ObjectId: 2.5.29.15 Criticality=true\nKeyUsage [\n  DigitalSignature\n]\n\n[9]: ObjectId: 2.5.29.17 Criticality=false\nSubjectAlternativeName [\n  DNSName: *.google.com\n]\n\n[10]: ObjectId: 2.5.29.14 Criticality=false\nSubjectKeyIdentifier [\nKeyIdentifier [\n0000: BA 16 19 65 61 DB B1 32   D3 8E E7 C6 A6 A5 CC A4  ...ea..2........\n0010: 3F 19 20 73                                        ?. s\n]\n]\n\n]\n  Algorithm: [SHA256withRSA]\n  Signature:\n0000: 52 3B 09 75 6D 73 2C 57   CE F5 6B F3 1F A8 5C FD  R;.ums,W..k...\\.\n0010: 0F F7 78 6D 02 9F DB 19   99 B1 9B A2 A5 42 7A 3B  ..xm.........Bz;\n0020: 0C 92 2C 65 F6 36 B8 15   28 5B 63 D2 7A 9D 34 94  ..,e.6..([c.z.4.\n0030: 6E 2E 40 82 E0 90 95 BE   B7 27 85 01 8F D7 25 6A  n.@......'....%j\n0040: 74 11 06 92 2C 6B 2F E7   D7 D3 AD BD 89 B3 C5 1F  t...,k/.........\n0050: 57 9B BB C6 43 79 8B 34   42 41 1C 80 A8 01 77 03  W...Cy.4BA....w.\n0060: 10 34 95 C4 B2 67 31 9D   2B 3B 5A 77 9D 96 7C 14  .4...g1.+;Zw....\n0070: F4 9A F3 E3 1C 18 08 60   CB 63 E1 17 EB 5C C2 B9  .......`.c...\\..\n0080: 21 4D 22 05 D7 63 E1 5B   D7 DD A6 E1 46 48 17 7D  !M\"..c.[....FH..\n0090: 10 54 FA 08 E3 43 DD F2   C7 41 A1 42 F7 EC D2 70  .T...C...A.B...p\n00A0: 5E 4A FB 8B 85 2E F4 A1   D1 3E AD 4E 39 72 21 AF  ^J.......\u003e.N9r!.\n00B0: B7 5B 9E 7D EB C0 29 91   7C 75 9F F7 7A 94 8C 46  .[....)..u..z..F\n00C0: FA 0B F7 A3 E9 49 6D B7   5D FE 68 49 E1 9F 18 B2  .....Im.].hI....\n00D0: A0 50 EB 93 8D 71 53 84   A2 34 C4 F8 C9 08 9D 5F  .P...qS..4....._\n00E0: 9B 2A 37 5E E0 F8 5D F5   7A 7D BC EB 3D 78 5C 23  .*7^..].z...=x\\#\n00F0: 84 DD CC 32 97 6C 77 92   7C 06 E4 5D 52 A0 5A 39  ...2.lw....]R.Z9\n\n]]\n```\n\n##### Logging detailed KeyManager flow, input and output\n```text\nSSLFactory sslFactory = SSLFactory.builder()\n        .withIdentityMaterial(Paths.get(\"/path/to/your/identity.jks\"), \"password\".toCharArray())\n        .withLoggingIdentityMaterial()\n        .withDefaultTrustMaterial()\n        .build();\n        \n// run your server or client and analyse the logs\n```\n\nYou will get a log message which is similar to the following one:\n```text\nAttempting to find a client alias for key types [EC], while also using the Socket. See below for list of the issuers:\n[CN=some-cn, OU=java-business-unit, O=thunderberry, C=NL]\nAttempting to find a client alias for key types [RSA], while also using the Socket. See below for list of the issuers:\n[CN=some-cn, OU=java-business-unit, O=thunderberry, C=NL]\nFound the following client aliases [my-client-alias] for key types [RSA], while also using the Socket. See below for list of the issuers:\n[CN=some-cn, OU=java-business-unit, O=thunderberry, C=NL]\nAttempting to get the private key for the alias: my-client-alias\nFound a private key for the alias: my-client-alias\nAttempting to get the certificate chain for the alias: my-client-alias\nFound the certificate chain with a size of 1 for the alias: my-client-alias. See below for the full chain:\n[[\n[\n  Version: V3\n  Subject: CN=some-cn, OU=java-business-unit, O=thunderberry, C=NL\n  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11\n\n  Key:  Sun RSA public key, 2048 bits\n  params: null\n  modulus: 24358361148173123789972454702359337497482540111137434929916055417657354571697209833398713022918665517266658129513432713825681637659966415899913132315999013865220594646161546243646863695313013179456071195691453898185614193141245291456731398570603932104743113343898797041713131938343069988939700047591424592896073860712253945927117061051481828014230668012078029149888844657841672769678941972627103264098329661131121121108364416406527046714029325801099459715576059589001573317998720822010338410175438085716969314224320362271384261147189938038370804394737540861857893390249061609350687279289599644929221019981684263046077\n  public exponent: 65537\n  Validity: [From: Mon Feb 08 18:14:16 CET 2021,\n               To: Thu Feb 06 18:14:16 CET 2031]\n  Issuer: CN=some-cn, OU=java-business-unit, O=thunderberry, C=NL\n  SerialNumber: [    3a03c719]\n\nCertificate Extensions: 3\n[1]: ObjectId: 2.5.29.37 Criticality=false\nExtendedKeyUsages [\n  serverAuth\n  clientAuth\n]\n\n[2]: ObjectId: 2.5.29.15 Criticality=false\nKeyUsage [\n  DigitalSignature\n  Key_Encipherment\n  Data_Encipherment\n  Key_Agreement\n]\n\n[3]: ObjectId: 2.5.29.14 Criticality=false\nSubjectKeyIdentifier [\nKeyIdentifier [\n0000: 6C D2 C6 3D 90 94 1F C9   43 9A A8 A3 41 3E BC 93  l..=....C...A\u003e..\n0010: FF E9 00 9E                                        ....\n]\n]\n\n]\n  Algorithm: [SHA256withRSA]\n  Signature:\n0000: 5F CD B8 0D 27 23 46 81   80 96 A0 E3 4D 79 82 F3  _...'#F.....My..\n0010: AC E4 FC 53 B6 8B 17 FD   88 E7 03 DF B5 A6 DC 78  ...S...........x\n0020: 75 D7 57 BE 14 C6 12 44   A3 25 E2 9B 2B E1 F1 FA  u.W....D.%..+...\n0030: 68 19 19 F3 1B E7 67 17   8F 12 F6 C7 82 CA B7 E2  h.....g.........\n0040: F9 66 44 09 3C D7 0F E1   0B FB CF 4B 58 37 79 32  .fD.\u003c......KX7y2\n0050: DC E1 E1 CD 97 9B 99 C8   95 DA F3 0E 74 0D 36 7E  ............t.6.\n0060: A4 E0 DA BC 66 A0 CD AD   0C BE 6D C5 12 7E F2 6E  ....f.....m....n\n0070: AC 89 00 55 1B 1A 23 CA   26 0D B3 B8 E5 52 8C F6  ...U..#.\u0026....R..\n0080: 20 D3 ED A3 D7 CD 55 2F   2D EB 07 12 1E 70 C6 0E   .....U/-....p..\n0090: 1F 3C AB 8C 23 2F 15 19   A4 F6 4E B0 0E F5 2A D9  .\u003c..#/....N...*.\n00A0: E1 F2 50 A9 BC 6D 7A 24   CA CA 07 69 61 0E 55 C5  ..P..mz$...ia.U.\n00B0: C3 36 72 2D B8 4A 93 2E   19 45 F9 49 C1 C8 14 15  .6r-.J...E.I....\n00C0: 99 C7 06 8D 2A 93 08 87   0B 89 BE 3D 72 01 A5 E7  ....*......=r...\n00D0: 97 2A B3 EA 63 92 45 32   D3 58 55 BE BB 69 B8 21  .*..c.E2.XU..i.!\n00E0: 5A 98 D2 7D 0B 8D BD 23   A2 3B C3 53 94 5A 54 BA  Z......#.;.S.ZT.\n00F0: F2 FD 48 AD 59 F6 E1 CB   86 BF EF 12 0E BD 69 1E  ..H.Y.........i.\n\n]]\n```\n\n### Fluently mapping SSLFactory\nThe SSLFactory can be mapped easily if it needs additional intermediate steps before it can be used fully used, such as using it with a Netty or Apache client. Below is an example for Netty with Spring WebClient.\n\n```java\nimport io.netty.handler.ssl.SslContext;\nimport nl.altindag.ssl.SSLFactory;\nimport nl.altindag.ssl.netty.util.NettySslUtils;\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport reactor.netty.http.client.HttpClient;\n\nimport javax.net.ssl.SSLException;\n\npublic class App {\n    \n    public static void main(String[] args) throws SSLException {\n      WebClient webClient = SSLFactory.builder()\n                .withDefaultTrustMaterial()\n                .build()\n                .map(NettySslUtils::forClient)\n                .map(SslContextBuilder::build)\n                .map(sslContext -\u003e HttpClient.create().secure(sslSpec -\u003e sslSpec.sslContext(sslContext)))\n                .map(ReactorClientHttpConnector::new)\n                .map(httpConnector -\u003e WebClient.builder().clientConnector(httpConnector).build()) \n                .get();\n    }\n\n}\n```\n\n\n### Returnable values from the SSLFactory\nThe SSLFactory provides different kinds of returnable values, see below for all the options:\n\n```java\nimport nl.altindag.ssl.SSLFactory;\nimport nl.altindag.ssl.model.KeyStoreHolder;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLEngine;\nimport javax.net.ssl.SSLParameters;\nimport javax.net.ssl.SSLServerSocketFactory;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.X509ExtendedKeyManager;\nimport javax.net.ssl.X509ExtendedTrustManager;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\nimport java.util.Optional;\n\npublic class App {\n\n    public static void main(String[] args) {\n        SSLFactory sslFactory = SSLFactory.builder()\n                .withIdentityMaterial(\"keystore.p12\", \"secret\".toCharArray(), \"PKCS12\")\n                .withTrustMaterial(\"truststore.p12\", \"secret\".toCharArray(), \"PKCS12\")\n                .build();\n\n        SSLContext sslContext = sslFactory.getSslContext();\n        HostnameVerifier hostnameVerifier = sslFactory.getHostnameVerifier();\n        Optional\u003cX509ExtendedKeyManager\u003e keyManager = sslFactory.getKeyManager();\n        Optional\u003cX509ExtendedTrustManager\u003e trustManager = sslFactory.getTrustManager();\n        Optional\u003cKeyManagerFactory\u003e keyManagerFactory = sslFactory.getKeyManagerFactory();\n        Optional\u003cTrustManagerFactory\u003e trustManagerFactory = sslFactory.getTrustManagerFactory();\n        List\u003cX509Certificate\u003e trustedCertificates = sslFactory.getTrustedCertificates();\n        SSLSocketFactory sslSocketFactory = sslFactory.getSslSocketFactory();\n        SSLServerSocketFactory sslServerSocketFactory = sslFactory.getSslServerSocketFactory();\n        SSLEngine sslEngine = sslFactory.getSslEngine(host, port);\n        SSLParameters sslParameters = sslFactory.getSslParameters();\n        List\u003cString\u003e ciphers = sslFactory.getCiphers();\n        List\u003cString\u003e protocols = sslFactory.getProtocols();\n    }\n\n}\n```\n\n### Additional mappers for specific libraries\nSome http clients relay on different ssl classes from third parties and require mapping from SSLFactory to those libraries.\nBelow you will find the maven dependency which will provide the mapping and also the SSLFactory library.\n#### Netty\nSome know http clients which relay on netty libraries are: [Spring WebFlux WebClient Netty](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html), [Async Http Client](https://github.com/AsyncHttpClient/async-http-client) and [Dispatch Reboot Http Client](https://github.com/dispatch/reboot).\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.hakky54\u003c/groupId\u003e\n  \u003cartifactId\u003eayza-for-netty\u003c/artifactId\u003e\n  \u003cversion\u003e10.0.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\nExample setup for Spring WebClient with Netty:\n```java\nimport io.netty.handler.ssl.SslContext;\nimport nl.altindag.ssl.SSLFactory;\nimport nl.altindag.ssl.netty.util.NettySslUtils;\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport reactor.netty.http.client.HttpClient;\n\nimport javax.net.ssl.SSLException;\n\npublic class App {\n    \n    public static void main(String[] args) throws SSLException {\n        SSLFactory sslFactory = SSLFactory.builder()\n                .withDefaultTrustMaterial()\n                .build();\n\n        SslContext sslContext = NettySslUtils.forClient(sslFactory).build();\n        HttpClient httpClient = HttpClient.create()\n                .secure(sslSpec -\u003e sslSpec.sslContext(sslContext));\n\n        WebClient webClient = WebClient.builder()\n                .clientConnector(new ReactorClientHttpConnector(httpClient))\n                .build();\n    }\n\n}\n```\n\n#### Jetty\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.hakky54\u003c/groupId\u003e\n  \u003cartifactId\u003eayza-for-jetty\u003c/artifactId\u003e\n  \u003cversion\u003e10.0.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\nExample setup for [Spring WebFlux WebClient Jetty](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html):\n```java\nimport nl.altindag.ssl.SSLFactory;\nimport nl.altindag.ssl.jetty.util.JettySslUtils;\nimport org.eclipse.jetty.client.HttpClient;\nimport org.eclipse.jetty.util.ssl.SslContextFactory;\nimport org.springframework.http.client.reactive.JettyClientHttpConnector;\nimport org.springframework.web.reactive.function.client.WebClient;\n\npublic class App {\n\n    public static void main(String[] args) {\n        SSLFactory sslFactory = SSLFactory.builder()\n                .withDefaultTrustMaterial()\n                .build();\n        \n        SslContextFactory.Client sslContextFactory = JettySslUtils.forClient(sslFactory);\n        HttpClient httpClient = new HttpClient(sslContextFactory);\n\n        WebClient webClient = WebClient.builder()\n                .clientConnector(new JettyClientHttpConnector(httpClient))\n                .build();\n    }\n\n}\n```\n\n#### Apache\n##### Apache 4\nApache Http Client works with javax.net.ssl.SSLContext, so an additional mapping to their library is not required.\nHowever, it is still possible to configure the http client with their custom configuration class. you can find below an example configuration for that use case:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.hakky54\u003c/groupId\u003e\n  \u003cartifactId\u003eayza-for-apache4\u003c/artifactId\u003e\n  \u003cversion\u003e10.0.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n```java\nimport nl.altindag.ssl.SSLFactory;\nimport nl.altindag.ssl.apache4.util.Apache4SslUtils;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.conn.socket.LayeredConnectionSocketFactory;\nimport org.apache.http.impl.client.HttpClients;\n\npublic class App {\n\n    public static void main(String[] args) {\n        SSLFactory sslFactory = SSLFactory.builder()\n                .withDefaultTrustMaterial()\n                .build();\n\n        LayeredConnectionSocketFactory socketFactory = Apache4SslUtils.toSocketFactory(sslFactory);\n\n        HttpClient httpClient = HttpClients.custom()\n                .setSSLSocketFactory(socketFactory)\n                .build();\n    }\n\n}\n```\n##### Apache 5\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.hakky54\u003c/groupId\u003e\n  \u003cartifactId\u003eayza-for-apache5\u003c/artifactId\u003e\n  \u003cversion\u003e10.0.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n```java\nimport nl.altindag.ssl.SSLFactory;\nimport nl.altindag.ssl.apache5.util.Apache5SslUtils;\nimport org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;\nimport org.apache.hc.client5.http.impl.async.HttpAsyncClients;\nimport org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;\nimport org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;\n\npublic class App {\n\n    public static void main(String[] args) {\n        SSLFactory sslFactory = SSLFactory.builder()\n                .withDefaultTrustMaterial()\n                .build();\n\n        PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()\n                .setTlsStrategy(Apache5SslUtils.toTlsStrategy(sslFactory))\n                .build();\n        \n        CloseableHttpAsyncClient httpAsyncClient = HttpAsyncClients.custom()\n                .setConnectionManager(connectionManager)\n                .build();\n        \n        httpAsyncClient.start();\n    }\n\n}\n```\n\n## Tested HTTP Clients\nBelow is a list of clients which have already been tested with examples, see in the [ClientConfig class](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/ClientConfig.java) and the [service directory](https://github.com/Hakky54/mutual-tls-ssl/tree/master/client/src/main/java/nl/altindag/client/service) for detailed configuration\n\n**Java**\n* [Apache HttpClient](https://hc.apache.org/httpcomponents-client-4.5.x/index.html) -\u003e [Client configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L68) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/ApacheHttpClientService.java)\n* [Apache HttpAsyncClient](https://hc.apache.org/httpcomponents-asyncclient-4.1.x/index.html) -\u003e [Client configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L76) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/ApacheHttpAsyncClientService.java)\n* [Apache 5 HttpClient](https://hc.apache.org/httpcomponents-client-5.0.x/examples.html) -\u003e [Client configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L86) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Apache5HttpClientService.java)\n* [Apache 5 HttpAsyncClient](https://hc.apache.org/httpcomponents-client-5.0.x/examples-async.html) -\u003e [Client configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L97) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Apache5HttpAsyncClientService.java)\n* [JDK HttpClient](https://openjdk.java.net/groups/net/httpclient/intro.html) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L111) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/JdkHttpClientService.java)\n* [Old JDK HttpClient](https://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html) -\u003e [Client Configuration \u0026 Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/OldJdkHttpClientService.java)\n* [Netty Reactor](https://github.com/reactor/reactor-netty) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L134) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/ReactorNettyService.java)\n* [Jetty Reactive HttpClient](https://github.com/jetty-project/jetty-reactive-httpclient) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L142) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/JettyReactiveHttpClientService.java)\n* [Spring RestTemplate](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L119) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/SpringRestTemplateService.java)\n* [Spring WebFlux WebClient Netty](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L148) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/SpringWebClientService.java)\n* [Spring WebFlux WebClient Jetty](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L155) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/SpringWebClientService.java)\n* [OkHttp](https://github.com/square/okhttp) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L125) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/OkHttpClientService.java)\n* [Jersey Client](https://eclipse-ee4j.github.io/jersey/) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L162) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/JerseyClientService.java)\n* Old Jersey Client -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L170) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/OldJerseyClientService.java)\n* [Apache CXF JAX-RS](https://cxf.apache.org/) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L182) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/ApacheCXFJaxRsClientService.java)\n* [Apache CXF using ConduitConfigurer](https://cxf.apache.org/) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L191) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/ApacheCXFWebClientService.java)\n* [Google HttpClient](https://github.com/googleapis/google-http-java-client) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L206) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/GoogleHttpClientService.java)\n* [Unirest](https://github.com/Kong/unirest-java) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L214) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/UnirestService.java)\n* [Retrofit](https://github.com/square/retrofit) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L224) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/RetrofitService.java)\n* [Async Http Client](https://github.com/AsyncHttpClient/async-http-client) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L262) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/AsyncHttpClientService.java)\n* [Feign](https://github.com/OpenFeign/feign) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L272) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/FeignService.java)\n* [Methanol](https://github.com/mizosoft/methanol) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L308) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/MethanolService.java)\n* [Vertx Webclient](https://github.com/vert-x3/vertx-web) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L316) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/VertxWebClientService.java)\n* [gRPC](https://grpc.io/) -\u003e [Client/Server Configuration \u0026 Example request](https://github.com/Hakky54/java-tutorials)\n* [ElasticSearch](https://www.elastic.co/) -\u003e [RestHighLevelClient Configuration \u0026 example request](https://github.com/Hakky54/java-tutorials/blob/main/elasticsearch-with-ssl/src/main/java/nl/altindag/ssl/es/App.java)\n* [Jetty WebSocket](https://www.eclipse.org/jetty/) -\u003e [Client configuration \u0026 example request](https://github.com/Hakky54/java-tutorials/blob/2bf5d975347d500bb9d0aa3b32cbf33b345425ee/websocket-client-with-ssl/src/main/java/nl/altindag/ssl/ws/App.java#L14)\n\n**Kotlin**\n* [Fuel](https://github.com/kittinunf/fuel) -\u003e [Client Configuration \u0026 Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/FuelService.kt)\n* [Http4k with Apache 4](https://github.com/http4k/http4k) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kApache4HttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kClientService.kt)\n* [Http4k with Async Apache 4](https://github.com/http4k/http4k) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kApache4AsyncHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kAsyncClientService.kt)\n* [Http4k with Apache 5](https://github.com/http4k/http4k) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kApache5HttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kClientService.kt)\n* [Http4k with Async Apache 5](https://github.com/http4k/http4k) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kApache5AsyncHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kAsyncClientService.kt)\n* [Http4k with Java Net](https://github.com/http4k/http4k) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kJavaHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kClientService.kt)\n* [Http4k with Jetty](https://github.com/http4k/http4k) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kJettyHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kClientService.kt)\n* [Http4k with OkHttp](https://github.com/http4k/http4k) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kOkHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4kClientService.kt)\n* [Kohttp](https://github.com/rybalkinsd/kohttp) -\u003e [Client Configuration \u0026 Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KohttpService.kt)\n* [Ktor with Android engine](https://github.com/ktorio/ktor) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorAndroidHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorHttpClientService.kt)\n* [Ktor with Apache engine](https://github.com/ktorio/ktor) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorApacheHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorHttpClientService.kt)\n* [Ktor with CIO (Coroutine-based I/O) engine](https://github.com/ktorio/ktor) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorCIOHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorHttpClientService.kt)\n* [Ktor with Java engine](https://github.com/ktorio/ktor) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorJavaHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorHttpClientService.kt)\n* [Ktor with Okhttp engine](https://github.com/ktorio/ktor) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorOkHttpClientService.kt) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/KtorHttpClientService.kt)\n\n**Scala**\n* [Twitter Finagle](https://github.com/twitter/finagle) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L233) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/FinagleHttpClientService.java)\n* [Twitter Finagle Featherbed](https://github.com/finagle/featherbed) -\u003e [Client Configuration \u0026 Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/d78e4e81b8b775d3ff09c11b0a7c1532a741199e/client/src/main/java/nl/altindag/client/service/FeatherbedRequestService.scala#L19)\n* [Akka Http Client](https://github.com/akka/akka-http) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/35cba2f3a2dcd73b01fa323b99eec7777f7429bb/client/src/main/java/nl/altindag/client/ClientConfig.java#L253) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/AkkaHttpClientService.java)\n* [Dispatch Reboot](https://github.com/dispatch/reboot) -\u003e [Client Configuration \u0026 Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/DispatchRebootService.scala)\n* [ScalaJ / Simplified Http Client](https://github.com/scalaj/scalaj-http) -\u003e [Client Configuration \u0026 Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/ScalaJHttpClientService.scala)\n* [Sttp](https://github.com/softwaremill/sttp) -\u003e [Client Configuration \u0026 Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/SttpHttpClientService.scala)\n* [Requests-Scala](https://github.com/lihaoyi/requests-scala) -\u003e [Client Configuration \u0026 Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/RequestsScalaService.scala)\n* [Http4s Blaze Client](https://github.com/http4s/http4s) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4sBlazeClientService.scala) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4sService.scala)\n* [Http4s Java Net Client](https://github.com/http4s/http4s) -\u003e [Client Configuration](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4sJavaNetClientService.scala) | [Example request](https://github.com/Hakky54/mutual-tls-ssl/blob/master/client/src/main/java/nl/altindag/client/service/Http4sService.scala)\n\nThere is a github project available named [Mutual-tls-ssl](https://github.com/Hakky54/mutual-tls-ssl) which provides a tutorial containing steps for setting up these four scenarios:\n* No security\n* One way authentication\n* Two way authentication\n* Two way authentication with trusting the Certificate Authority\n\nIt will also explain how to create KeyStores, Certificates, Certificate Signing Requests and how to implement it.\n\n## Contributing\n\nThere are plenty of ways to contribute to this project:\n\n* Give it a star\n* Make a donation through [GitHub](https://github.com/sponsors/Hakky54) or [open collective](https://opencollective.com/hakky54)\n* Join the [Gitter room](https://gitter.im/hakky54/ayza) and leave a feedback or help with answering users questions\n* Submit a PR\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/MrR0807\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/24605837?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eLaurynas\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3AMrR0807\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#maintenance-MrR0807\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/charphi\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/8778378?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePhilippe Charles\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Acharphi\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://tadhgpearson.wordpress.com\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1496586?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eTadhg Pearson\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Atadhgpearson\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/winster\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/2383613?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ewinster\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Awinster\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/lalloni\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/84328?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePablo Lalloni\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Alalloni\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/luismospinam\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/25059970?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eLuis Miguel Ospina\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Aluismospinam\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/Athou\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1256795?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJérémie Panzer\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3AAthou\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/patpatpat123\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/43899031?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003epatpatpat123\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Apatpatpat123\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Apatpatpat123\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://codyaray.com\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/44062?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eCody A. Ray\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/search?q=Cody%20Ray\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/chibenwa\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/6928740?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eBenoit Tellier\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Achibenwa\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/sal0max\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/423373?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003esal0max\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Asal0max\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/lhstack\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/42345796?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003elhstack\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Alhstack\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/dasteg\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/3967403?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003edasteg\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Adasteg\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/rymsha\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/2891483?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003erymsha\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Arymsha\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/manbucy\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/24501621?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003emanbucy\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Amanbucy\" title=\"Code and Bug reports\"\u003e🐛 💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/swankjesse\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/133019?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eswankjesse\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Aswankjesse\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/ivenhov\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/778457?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eivenhov\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Aivenhov\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/ecki\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/361432?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eecki\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Aecki\" title=\"Code and Bug reports\"\u003e🐛 💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/mbenson\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/487462?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003embenson\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e \u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Ambenson\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Ambenson\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/EugenMayer\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/136934?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eEugenMayer\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e \u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3AEugenMayer\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/bjorndarri\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/2327926?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ebjorndarri\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e \u003ca href=\"https://github.com/Hakky54/ayza/issues?q=bjorndarri\" title=\"Code and Ideas, Planning, \u0026 Feedback\"\u003e🤔 💻\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/henryju\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/281596?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ehenryju\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e \u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Ahenryju\" title=\"Code and Ideas, Planning, \u0026 Feedback\"\u003e🤔 💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/nquinquenel\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/14952624?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003enquinquenel\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Anquinquenel\" title=\"Code and Bug reports\"\u003e🐛 💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/woj-tek\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/724413?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ewoj-tek\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/thahnen\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/6588381?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ethahnen\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Athahnen\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/gerardnorton\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/62466694?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003egerardnorton\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Agerardnorton\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/austinarbor\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/11469880?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eaustinarbor\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Aaustinarbor\" title=\"Bug reports and Ideas, Planning, \u0026 Feedback\"\u003e🐛 🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/ssmoss\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/8904909?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003essmoss\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Assmoss\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/maxxedev\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/5051664?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003emaxxedev\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e \u003ca href=\"https://github.com/Hakky54/ayza/issues?q=author%3Amaxxedev\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\n## License\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FHakky54%2Fayza.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FHakky54%2Fayza?ref=badge_large)","funding_links":["https://github.com/sponsors/Hakky54","https://opencollective.com/hakky54","https://ko-fi.com/hakky54"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhakky54%2Fsslcontext-kickstart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhakky54%2Fsslcontext-kickstart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhakky54%2Fsslcontext-kickstart/lists"}