Remove local truststore for Let's Encrypt servers

pull/55/head
Richard Körber 2017-09-20 20:58:52 +02:00
parent e15abb0ca0
commit 148c98d673
6 changed files with 4 additions and 174 deletions

View File

@ -12,7 +12,7 @@ It is an independent open source implementation that is not affiliated with or e
* Fully supports the ACME v2 protocol
* Easy to use Java API
* Requires JRE 8 or higher
* Requires JRE 8 (update 101) or higher
* Built with maven, packages available at [Maven Central](http://search.maven.org/#search|ga|1|g%3A%22org.shredzone.acme4j%22)
* Small, only requires [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home) and [slf4j](http://www.slf4j.org/) as dependencies
* Extensive unit and integration tests

View File

@ -17,7 +17,6 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import org.shredzone.acme4j.connector.HttpConnector;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.provider.AbstractAcmeProvider;
import org.shredzone.acme4j.provider.AcmeProvider;
@ -28,8 +27,7 @@ import org.shredzone.acme4j.provider.AcmeProvider;
* The {@code serverUri} is {@code "acme://letsencrypt.org"} for the production server,
* and {@code "acme://letsencrypt.org/staging"} for a testing server.
* <p>
* If you want to use <em>Let's Encrypt</em>, always prefer to use this provider, as it
* takes care for the correct connection and SSL certificates.
* If you want to use <em>Let's Encrypt</em>, always prefer to use this provider.
*
* @see <a href="https://letsencrypt.org/">Let's Encrypt</a>
*/
@ -63,9 +61,4 @@ public class LetsEncryptAcmeProvider extends AbstractAcmeProvider {
}
}
@Override
protected HttpConnector createHttpConnector() {
return new LetsEncryptHttpConnector();
}
}

View File

@ -1,75 +0,0 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2015 Richard "Shred" Körber
* http://acme4j.shredzone.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.shredzone.acme4j.provider.letsencrypt;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import org.shredzone.acme4j.connector.HttpConnector;
/**
* {@link HttpConnector} to be used for Let's Encrypt. It is pinned to the Let's Encrypt
* server certificate.
*/
public class LetsEncryptHttpConnector extends HttpConnector {
private static SSLSocketFactory sslSocketFactory;
@Override
public HttpURLConnection openConnection(URL url) throws IOException {
HttpURLConnection conn = super.openConnection(url);
if (conn instanceof HttpsURLConnection) {
((HttpsURLConnection) conn).setSSLSocketFactory(createSocketFactory());
}
return conn;
}
/**
* Lazily creates an {@link SSLSocketFactory} that exclusively accepts the Let's
* Encrypt certificate.
*/
protected synchronized SSLSocketFactory createSocketFactory() throws IOException {
if (sslSocketFactory == null) {
try {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(getClass().getResourceAsStream("/org/shredzone/acme4j/letsencrypt.truststore"),
"acme4j".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keystore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
sslSocketFactory = ctx.getSocketFactory();
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException
| KeyManagementException ex) {
throw new IOException("Could not create truststore", ex);
}
}
return sslSocketFactory;
}
}

View File

@ -1,80 +0,0 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2015 Richard "Shred" Körber
* http://acme4j.shredzone.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.shredzone.acme4j.provider.letsencrypt;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSocketFactory;
import org.junit.Test;
import org.junit.experimental.categories.Category;
/**
* Unit test for {@link LetsEncryptHttpConnector}.
*/
public class LetsEncryptHttpConnectorTest {
/**
* Test if the connector accepts only the Let's Encrypt certificate.
* <p>
* This test requires a network connection. It should be excluded from automated
* builds.
*/
@Test
@Category(HttpURLConnection.class)
public void testCertificate() throws IOException {
LetsEncryptHttpConnector connector = new LetsEncryptHttpConnector();
try {
HttpURLConnection goodConn = connector.openConnection(
new URL("https://acme-staging.api.letsencrypt.org/directory"));
assertThat(goodConn, is(instanceOf(HttpsURLConnection.class)));
goodConn.connect();
} catch (SSLHandshakeException ex) {
fail("Connection does not accept Let's Encrypt certificate");
}
try {
HttpURLConnection badConn = connector.openConnection(
new URL("https://www.google.com"));
assertThat(badConn, is(instanceOf(HttpsURLConnection.class)));
badConn.connect();
fail("Connection accepts foreign certificate");
} catch (SSLHandshakeException ex) {
// expected
}
}
/**
* Test that the {@link SSLSocketFactory} can be instantiated and is cached.
*/
@Test
public void testCreateSocketFactory() throws IOException {
LetsEncryptHttpConnector connector = new LetsEncryptHttpConnector();
SSLSocketFactory factory1 = connector.createSocketFactory();
assertThat(factory1, is(notNullValue()));
SSLSocketFactory factory2 = connector.createSocketFactory();
assertThat(factory1, is(sameInstance(factory2)));
}
}

View File

@ -7,14 +7,6 @@ Web site: [Let's Encrypt](https://letsencrypt.org)
* `acme://letsencrypt.org` - Production server
* `acme://letsencrypt.org/staging` - Testing server
## Features
## Note
* Accepts the ACME server certificate of Let's Encrypt even on older Java versions
## Limits
* Registrations per IP: 10 per 3 hours
* Certificates per Domain: 5 per 7 days
* SANs per Certificate: 100
See [here](https://community.letsencrypt.org/t/public-beta-rate-limits/4772) for the current limits.
* Java 8u101 or higher is required for connecting to the _Let's Encrypt_ servers.