mirror of https://github.com/shred/acme4j
Remove deprecated code
parent
f44b62d3cf
commit
0465d1941a
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* acme4j - Java ACME client
|
||||
*
|
||||
* Copyright (C) 2016 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.challenge;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.shredzone.acme4j.Session;
|
||||
|
||||
/**
|
||||
* Implements the {@value TYPE} challenge.
|
||||
*
|
||||
* @deprecated This challenge has been removed from the ACMEv2 specs.
|
||||
*/
|
||||
@Deprecated
|
||||
public class OutOfBand01Challenge extends Challenge {
|
||||
private static final long serialVersionUID = -7459595198486630582L;
|
||||
|
||||
/**
|
||||
* Challenge type name: {@value}
|
||||
*/
|
||||
public static final String TYPE = "oob-01";
|
||||
|
||||
/**
|
||||
* Creates a new generic {@link OutOfBand01Challenge} object.
|
||||
*
|
||||
* @param session
|
||||
* {@link Session} to bind to.
|
||||
*/
|
||||
public OutOfBand01Challenge(Session session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the validation URL to be visited by the customer in order to complete the
|
||||
* challenge.
|
||||
*/
|
||||
public URL getValidationUrl() {
|
||||
return getJSON().get("href").asURL();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,68 +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.challenge;
|
||||
|
||||
import static org.shredzone.acme4j.toolbox.AcmeUtils.*;
|
||||
|
||||
import org.shredzone.acme4j.Session;
|
||||
|
||||
/**
|
||||
* Implements the {@value TYPE} challenge.
|
||||
*
|
||||
* @deprecated This challenge is vulnerable and will be removed from the ACME specs. Do
|
||||
* not use! Let's Encrypt does not offer this challenge to the general public
|
||||
* any more.
|
||||
*/
|
||||
@Deprecated
|
||||
public class TlsSni01Challenge extends TokenChallenge {
|
||||
private static final long serialVersionUID = 7370329525205430573L;
|
||||
|
||||
/**
|
||||
* Challenge type name: {@value}
|
||||
*/
|
||||
public static final String TYPE = "tls-sni-01";
|
||||
|
||||
private String subject;
|
||||
|
||||
/**
|
||||
* Creates a new generic {@link TlsSni01Challenge} object.
|
||||
*
|
||||
* @param session
|
||||
* {@link Session} to bind to.
|
||||
*/
|
||||
public TlsSni01Challenge(Session session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the subject to generate a self-signed certificate for.
|
||||
*/
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean acceptable(String type) {
|
||||
return TYPE.equals(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void authorize() {
|
||||
super.authorize();
|
||||
|
||||
String hash = hexEncode(sha256hash(getAuthorization()));
|
||||
subject = hash.substring(0, 32) + '.' + hash.substring(32) + ".acme.invalid";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* acme4j - Java ACME client
|
||||
*
|
||||
* Copyright (C) 2016 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.challenge;
|
||||
|
||||
import static org.shredzone.acme4j.toolbox.AcmeUtils.*;
|
||||
|
||||
import org.shredzone.acme4j.Session;
|
||||
|
||||
/**
|
||||
* Implements the {@value TYPE} challenge.
|
||||
*
|
||||
* @deprecated This challenge is vulnerable and will be removed from the ACME specs. Do
|
||||
* not use!
|
||||
*/
|
||||
@Deprecated
|
||||
public class TlsSni02Challenge extends TokenChallenge {
|
||||
private static final long serialVersionUID = 8921833167878544518L;
|
||||
|
||||
/**
|
||||
* Challenge type name: {@value}
|
||||
*/
|
||||
public static final String TYPE = "tls-sni-02";
|
||||
|
||||
private String subject;
|
||||
private String sanB;
|
||||
|
||||
/**
|
||||
* Creates a new generic {@link TlsSni02Challenge} object.
|
||||
*
|
||||
* @param session
|
||||
* {@link Session} to bind to.
|
||||
*/
|
||||
public TlsSni02Challenge(Session session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subject, which is to be used as "SAN-A" in a self-signed certificate.
|
||||
* The CA will send the SNI request against this domain.
|
||||
*/
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key authorization, which is to be used as "SAN-B" in a self-signed
|
||||
* certificate.
|
||||
*/
|
||||
public String getSanB() {
|
||||
return sanB;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean acceptable(String type) {
|
||||
return TYPE.equals(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void authorize() {
|
||||
super.authorize();
|
||||
|
||||
String tokenHash = hexEncode(sha256hash(getToken()));
|
||||
subject = tokenHash.substring(0, 32) + '.' + tokenHash.substring(32) + ".token.acme.invalid";
|
||||
|
||||
String kaHash = hexEncode(sha256hash(getAuthorization()));
|
||||
sanB = kaHash.substring(0, 32) + '.' + kaHash.substring(32) + ".ka.acme.invalid";
|
||||
}
|
||||
|
||||
}
|
|
@ -25,9 +25,6 @@ import org.shredzone.acme4j.Session;
|
|||
import org.shredzone.acme4j.challenge.Challenge;
|
||||
import org.shredzone.acme4j.challenge.Dns01Challenge;
|
||||
import org.shredzone.acme4j.challenge.Http01Challenge;
|
||||
import org.shredzone.acme4j.challenge.OutOfBand01Challenge;
|
||||
import org.shredzone.acme4j.challenge.TlsSni01Challenge;
|
||||
import org.shredzone.acme4j.challenge.TlsSni02Challenge;
|
||||
import org.shredzone.acme4j.connector.Connection;
|
||||
import org.shredzone.acme4j.connector.DefaultConnection;
|
||||
import org.shredzone.acme4j.connector.HttpConnector;
|
||||
|
@ -41,7 +38,6 @@ import org.shredzone.acme4j.toolbox.JSON;
|
|||
* Implementing classes must implement at least {@link AcmeProvider#accepts(URI)}
|
||||
* and {@link AbstractAcmeProvider#resolve(URI)}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class AbstractAcmeProvider implements AcmeProvider {
|
||||
|
||||
private static final Map<String, Function<Session, Challenge>> CHALLENGES = challengeMap();
|
||||
|
@ -68,10 +64,7 @@ public abstract class AbstractAcmeProvider implements AcmeProvider {
|
|||
Map<String, Function<Session, Challenge>> map = new HashMap<>();
|
||||
|
||||
map.put(Dns01Challenge.TYPE, Dns01Challenge::new);
|
||||
map.put(TlsSni01Challenge.TYPE, TlsSni01Challenge::new);
|
||||
map.put(TlsSni02Challenge.TYPE, TlsSni02Challenge::new);
|
||||
map.put(Http01Challenge.TYPE, Http01Challenge::new);
|
||||
map.put(OutOfBand01Challenge.TYPE, OutOfBand01Challenge::new);
|
||||
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import org.junit.Test;
|
|||
import org.shredzone.acme4j.challenge.Challenge;
|
||||
import org.shredzone.acme4j.challenge.Dns01Challenge;
|
||||
import org.shredzone.acme4j.challenge.Http01Challenge;
|
||||
import org.shredzone.acme4j.challenge.TlsSni02Challenge;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
|
||||
import org.shredzone.acme4j.provider.TestableConnectionProvider;
|
||||
|
@ -40,7 +39,6 @@ import org.shredzone.acme4j.toolbox.JSONBuilder;
|
|||
/**
|
||||
* Unit tests for {@link Authorization}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class AuthorizationTest {
|
||||
|
||||
private static final String SNAILMAIL_TYPE = "snail-01"; // a non-existent challenge
|
||||
|
@ -63,10 +61,6 @@ public class AuthorizationTest {
|
|||
Challenge c2 = authorization.findChallenge(Http01Challenge.TYPE);
|
||||
assertThat(c2, is(notNullValue()));
|
||||
assertThat(c2, is(instanceOf(Http01Challenge.class)));
|
||||
|
||||
// TlsSniChallenge is available, but not as standalone challenge
|
||||
Challenge c3 = authorization.findChallenge(TlsSni02Challenge.TYPE);
|
||||
assertThat(c3, is(nullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,31 +78,19 @@ public class AuthorizationTest {
|
|||
assertThat(c1, contains(instanceOf(Http01Challenge.class)));
|
||||
|
||||
// Available combined challenge
|
||||
Collection<Challenge> c2 = authorization.findCombination(Dns01Challenge.TYPE, TlsSni02Challenge.TYPE);
|
||||
assertThat(c2, hasSize(2));
|
||||
assertThat(c2, contains(instanceOf(Dns01Challenge.class),
|
||||
instanceOf(TlsSni02Challenge.class)));
|
||||
Collection<Challenge> c2 = authorization.findCombination(Dns01Challenge.TYPE, Http01Challenge.TYPE);
|
||||
assertThat(c2, hasSize(1));
|
||||
assertThat(c2, contains(instanceOf(Http01Challenge.class)));
|
||||
|
||||
// Order does not matter
|
||||
Collection<Challenge> c3 = authorization.findCombination(TlsSni02Challenge.TYPE, Dns01Challenge.TYPE);
|
||||
assertThat(c3, hasSize(2));
|
||||
assertThat(c3, contains(instanceOf(Dns01Challenge.class),
|
||||
instanceOf(TlsSni02Challenge.class)));
|
||||
Collection<Challenge> c3 = authorization.findCombination(Http01Challenge.TYPE, Dns01Challenge.TYPE);
|
||||
assertThat(c3, hasSize(1));
|
||||
assertThat(c3, contains(instanceOf(Http01Challenge.class)));
|
||||
|
||||
// Finds smaller combinations as well
|
||||
Collection<Challenge> c4 = authorization.findCombination(Dns01Challenge.TYPE, TlsSni02Challenge.TYPE, SNAILMAIL_TYPE);
|
||||
assertThat(c4, hasSize(2));
|
||||
assertThat(c4, contains(instanceOf(Dns01Challenge.class),
|
||||
instanceOf(TlsSni02Challenge.class)));
|
||||
|
||||
// Finds the smallest possible combination
|
||||
Collection<Challenge> c5 = authorization.findCombination(Dns01Challenge.TYPE, TlsSni02Challenge.TYPE, Http01Challenge.TYPE);
|
||||
assertThat(c5, hasSize(1));
|
||||
assertThat(c5, contains(instanceOf(Http01Challenge.class)));
|
||||
|
||||
// Finds only entire combinations
|
||||
Collection<Challenge> c6 = authorization.findCombination(Dns01Challenge.TYPE);
|
||||
assertThat(c6, is(empty()));
|
||||
Collection<Challenge> c4 = authorization.findCombination(Dns01Challenge.TYPE, Http01Challenge.TYPE, SNAILMAIL_TYPE);
|
||||
assertThat(c4, hasSize(1));
|
||||
assertThat(c4, contains(instanceOf(Http01Challenge.class)));
|
||||
|
||||
// Does not find challenges that have not been provided
|
||||
Collection<Challenge> c7 = authorization.findCombination(SNAILMAIL_TYPE);
|
||||
|
@ -327,7 +309,6 @@ public class AuthorizationTest {
|
|||
|
||||
provider.putTestChallenge(Http01Challenge.TYPE, new Http01Challenge(session));
|
||||
provider.putTestChallenge(Dns01Challenge.TYPE, new Dns01Challenge(session));
|
||||
provider.putTestChallenge(TlsSni02Challenge.TYPE, new TlsSni02Challenge(session));
|
||||
|
||||
Authorization authorization = new Authorization(session, locationUrl);
|
||||
authorization.unmarshalAuthorization(getJsonAsObject("authorizationChallenges"));
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* acme4j - Java ACME client
|
||||
*
|
||||
* Copyright (C) 2016 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.challenge;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.shredzone.acme4j.toolbox.TestUtils.getJsonAsObject;
|
||||
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.shredzone.acme4j.Session;
|
||||
import org.shredzone.acme4j.Status;
|
||||
import org.shredzone.acme4j.toolbox.JSONBuilder;
|
||||
import org.shredzone.acme4j.toolbox.TestUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link OutOfBand01Challenge}.
|
||||
*/
|
||||
public class OutOfBandChallengeTest {
|
||||
private static Session session;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws IOException {
|
||||
session = TestUtils.session();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that {@link OutOfBand01Challenge} is returning the validation URL.
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void testHttpChallenge() throws IOException {
|
||||
OutOfBand01Challenge challenge = new OutOfBand01Challenge(session);
|
||||
challenge.unmarshall(getJsonAsObject("oobChallenge"));
|
||||
|
||||
assertThat(challenge.getType(), is(OutOfBand01Challenge.TYPE));
|
||||
assertThat(challenge.getStatus(), is(Status.PENDING));
|
||||
assertThat(challenge.getValidationUrl(),
|
||||
is(new URL("https://example.com/validate/evaGxfADs6pSRb2LAv9IZ")));
|
||||
|
||||
JSONBuilder cb = new JSONBuilder();
|
||||
challenge.respond(cb);
|
||||
|
||||
assertThat(cb.toString(), sameJSONAs("{\"type\": \"oob-01\"}"));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,64 +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.challenge;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.shredzone.acme4j.toolbox.TestUtils.getJsonAsObject;
|
||||
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.shredzone.acme4j.Session;
|
||||
import org.shredzone.acme4j.Status;
|
||||
import org.shredzone.acme4j.toolbox.JSONBuilder;
|
||||
import org.shredzone.acme4j.toolbox.TestUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TlsSni01Challenge}.
|
||||
*/
|
||||
public class TlsSni01ChallengeTest {
|
||||
private static final String KEY_AUTHORIZATION =
|
||||
"VNLBdSiZ3LppU2CRG8bilqlwq4DuApJMg3ZJowU6JhQ.HnWjTDnyqlCrm6tZ-6wX-TrEXgRdeNu9G71gqxSO6o0";
|
||||
|
||||
private static Session session;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws IOException {
|
||||
session = TestUtils.session();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that {@link TlsSni01Challenge} generates a correct authorization key.
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void testTlsSniChallenge() throws IOException {
|
||||
TlsSni01Challenge challenge = new TlsSni01Challenge(session);
|
||||
challenge.unmarshall(getJsonAsObject("tlsSniChallenge"));
|
||||
|
||||
assertThat(challenge.getType(), is(TlsSni01Challenge.TYPE));
|
||||
assertThat(challenge.getStatus(), is(Status.PENDING));
|
||||
assertThat(challenge.getSubject(), is("14e2350a04434f93c2e0b6012968d99d.ed459b6a7a019d9695609b8514f9d63d.acme.invalid"));
|
||||
|
||||
JSONBuilder cb = new JSONBuilder();
|
||||
challenge.respond(cb);
|
||||
|
||||
assertThat(cb.toString(), sameJSONAs("{\"keyAuthorization\"=\""
|
||||
+ KEY_AUTHORIZATION + "\"}").allowingExtraUnexpectedFields());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* acme4j - Java ACME client
|
||||
*
|
||||
* Copyright (C) 2016 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.challenge;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.shredzone.acme4j.toolbox.TestUtils.getJsonAsObject;
|
||||
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.shredzone.acme4j.Session;
|
||||
import org.shredzone.acme4j.Status;
|
||||
import org.shredzone.acme4j.toolbox.JSONBuilder;
|
||||
import org.shredzone.acme4j.toolbox.TestUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TlsSni02Challenge}.
|
||||
*/
|
||||
public class TlsSni02ChallengeTest {
|
||||
private static final String KEY_AUTHORIZATION =
|
||||
"VNLBdSiZ3LppU2CRG8bilqlwq4DuApJMg3ZJowU6JhQ.HnWjTDnyqlCrm6tZ-6wX-TrEXgRdeNu9G71gqxSO6o0";
|
||||
|
||||
private static Session session;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws IOException {
|
||||
session = TestUtils.session();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that {@link TlsSni02Challenge} generates a correct authorization key.
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void testTlsSni02Challenge() throws IOException {
|
||||
TlsSni02Challenge challenge = new TlsSni02Challenge(session);
|
||||
challenge.unmarshall(getJsonAsObject("tlsSni02Challenge"));
|
||||
|
||||
assertThat(challenge.getType(), is(TlsSni02Challenge.TYPE));
|
||||
assertThat(challenge.getStatus(), is(Status.PENDING));
|
||||
assertThat(challenge.getSubject(), is("5bf0b9908ed73bc53ed3327afa52f76b.0a4bea00520f0753f42abe0bb39e3ea8.token.acme.invalid"));
|
||||
assertThat(challenge.getSanB(), is("14e2350a04434f93c2e0b6012968d99d.ed459b6a7a019d9695609b8514f9d63d.ka.acme.invalid"));
|
||||
|
||||
JSONBuilder cb = new JSONBuilder();
|
||||
challenge.respond(cb);
|
||||
|
||||
assertThat(cb.toString(), sameJSONAs("{\"keyAuthorization\"=\""
|
||||
+ KEY_AUTHORIZATION + "\"}").allowingExtraUnexpectedFields());
|
||||
}
|
||||
|
||||
}
|
|
@ -30,8 +30,6 @@ import org.shredzone.acme4j.Session;
|
|||
import org.shredzone.acme4j.challenge.Challenge;
|
||||
import org.shredzone.acme4j.challenge.Dns01Challenge;
|
||||
import org.shredzone.acme4j.challenge.Http01Challenge;
|
||||
import org.shredzone.acme4j.challenge.OutOfBand01Challenge;
|
||||
import org.shredzone.acme4j.challenge.TlsSni02Challenge;
|
||||
import org.shredzone.acme4j.connector.Connection;
|
||||
import org.shredzone.acme4j.connector.DefaultConnection;
|
||||
import org.shredzone.acme4j.connector.HttpConnector;
|
||||
|
@ -41,7 +39,6 @@ import org.shredzone.acme4j.toolbox.TestUtils;
|
|||
/**
|
||||
* Unit tests for {@link AbstractAcmeProvider}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class AbstractAcmeProviderTest {
|
||||
|
||||
/**
|
||||
|
@ -148,21 +145,9 @@ public class AbstractAcmeProviderTest {
|
|||
assertThat(c3, not(nullValue()));
|
||||
assertThat(c3, instanceOf(Dns01Challenge.class));
|
||||
|
||||
Challenge c4 = provider.createChallenge(session, org.shredzone.acme4j.challenge.TlsSni01Challenge.TYPE);
|
||||
assertThat(c4, not(nullValue()));
|
||||
assertThat(c4, instanceOf(org.shredzone.acme4j.challenge.TlsSni01Challenge.class));
|
||||
|
||||
Challenge c5 = provider.createChallenge(session, TlsSni02Challenge.TYPE);
|
||||
assertThat(c5, not(nullValue()));
|
||||
assertThat(c5, instanceOf(TlsSni02Challenge.class));
|
||||
|
||||
Challenge c6 = provider.createChallenge(session, "foobar-01");
|
||||
assertThat(c6, is(nullValue()));
|
||||
|
||||
Challenge c7 = provider.createChallenge(session, OutOfBand01Challenge.TYPE);
|
||||
assertThat(c7, not(nullValue()));
|
||||
assertThat(c7, instanceOf(OutOfBand01Challenge.class));
|
||||
|
||||
Challenge c8 = provider.createChallenge(session, "");
|
||||
assertThat(c8, is(nullValue()));
|
||||
|
||||
|
|
|
@ -201,14 +201,9 @@ authorizationChallenges = \
|
|||
"type": "dns-01",\
|
||||
"uri": "https://example.com/authz/asdf/1",\
|
||||
"token": "DGyRejmCefe7v4NfDGDKfA"\
|
||||
},\
|
||||
{\
|
||||
"type": "tls-sni-02",\
|
||||
"uri": "https://example.com/authz/asdf/2",\
|
||||
"token": "VNLBdSiZ3LppU2CRG8bilqlwq4DuApJMg3ZJowU6JhQ"\
|
||||
}\
|
||||
],\
|
||||
"combinations": [[0], [1,2]]\
|
||||
"combinations": [[0],[1]]\
|
||||
}
|
||||
|
||||
|
||||
|
@ -245,24 +240,4 @@ httpNoTokenChallenge = \
|
|||
"status":"pending" \
|
||||
}
|
||||
|
||||
tlsSniChallenge = \
|
||||
{ \
|
||||
"type":"tls-sni-01", \
|
||||
"status":"pending", \
|
||||
"token": "VNLBdSiZ3LppU2CRG8bilqlwq4DuApJMg3ZJowU6JhQ" \
|
||||
}
|
||||
|
||||
tlsSni02Challenge = \
|
||||
{ \
|
||||
"type":"tls-sni-02", \
|
||||
"status":"pending", \
|
||||
"token": "VNLBdSiZ3LppU2CRG8bilqlwq4DuApJMg3ZJowU6JhQ" \
|
||||
}
|
||||
|
||||
oobChallenge = \
|
||||
{ \
|
||||
"type": "oob-01", \
|
||||
"href": "https://example.com/validate/evaGxfADs6pSRb2LAv9IZ" \
|
||||
}
|
||||
|
||||
#
|
|
@ -132,22 +132,6 @@ public final class CertificateUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an X.509 certificate chain PEM file.
|
||||
*
|
||||
* @param chain
|
||||
* {@link X509Certificate[]} to write
|
||||
* @param w
|
||||
* {@link Writer} to write the PEM file to. The {@link Writer} is closed
|
||||
* after use.
|
||||
* @deprecated Use
|
||||
* {@link #writeX509CertificateChain(Writer, X509Certificate, X509Certificate...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static void writeX509CertificateChain(X509Certificate[] chain, Writer w) throws IOException {
|
||||
writeX509CertificateChain(w, null, chain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a CSR PEM file.
|
||||
*
|
||||
|
@ -166,43 +150,6 @@ public final class CertificateUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a self-signed {@link X509Certificate} that can be used for
|
||||
* {@link org.shredzone.acme4j.challenge.TlsSni01Challenge}. The certificate is valid
|
||||
* for 7 days.
|
||||
*
|
||||
* @param keypair
|
||||
* A domain {@link KeyPair} to be used for the challenge
|
||||
* @param subject
|
||||
* Subject to create a certificate for
|
||||
* @return Created certificate
|
||||
* @deprecated The tls-sni-01 challenge is deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public static X509Certificate createTlsSniCertificate(KeyPair keypair, String subject) throws IOException {
|
||||
return createCertificate(keypair, subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a self-signed {@link X509Certificate} that can be used for
|
||||
* {@link org.shredzone.acme4j.challenge.TlsSni02Challenge}. The certificate is valid
|
||||
* for 7 days.
|
||||
*
|
||||
* @param keypair
|
||||
* A domain {@link KeyPair} to be used for the challenge
|
||||
* @param sanA
|
||||
* SAN-A to be used in the certificate
|
||||
* @param sanB
|
||||
* SAN-B to be used in the certificate
|
||||
* @return Created certificate
|
||||
* @deprecated The tls-sni-02 challenge is deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public static X509Certificate createTlsSni02Certificate(KeyPair keypair, String sanA, String sanB)
|
||||
throws IOException {
|
||||
return createCertificate(keypair, sanA, sanB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a generic self-signed challenge {@link X509Certificate}. The certificate is
|
||||
* valid for 7 days.
|
||||
|
|
|
@ -28,9 +28,6 @@ import java.security.cert.CertificateException;
|
|||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateParsingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -121,55 +118,6 @@ public class CertificateUtilsTest {
|
|||
assertThat(countCertificates(out), is(3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if {@link CertificateUtils#createTlsSniCertificate(KeyPair, String)} creates a
|
||||
* good certificate.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testCreateTlsSniCertificate() throws IOException, CertificateParsingException {
|
||||
String subject = "30c452b9bd088cdbc2c4094947025d7c.7364ea602ac325a1b55ceaae024fbe29.acme.invalid";
|
||||
|
||||
KeyPair keypair = KeyPairUtils.createKeyPair(2048);
|
||||
|
||||
X509Certificate cert = CertificateUtils.createTlsSniCertificate(keypair, subject);
|
||||
|
||||
Instant now = Instant.now();
|
||||
Instant end = now.plus(Duration.ofDays(8));
|
||||
|
||||
assertThat(cert, not(nullValue()));
|
||||
assertThat(cert.getNotAfter(), is(greaterThan(Date.from(now))));
|
||||
assertThat(cert.getNotAfter(), is(lessThan(Date.from(end))));
|
||||
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(Date.from(now))));
|
||||
assertThat(cert.getSubjectX500Principal().getName(), is("CN=acme.invalid"));
|
||||
assertThat(getSANs(cert), containsInAnyOrder(subject));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if {@link CertificateUtils#createTlsSni02Certificate(KeyPair, String, String)}
|
||||
* creates a good certificate.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testCreateTlsSni02Certificate() throws IOException, CertificateParsingException {
|
||||
String sanA = "1082909237a535173c8415a44539f84e.248317530d8d1a0c71de8fd23f1beae4.token.acme.invalid";
|
||||
String sanB = "edc3a1d40199c1723358d57853bc23ff.4d4473417a6d76e80df17bbcfbe53d2c.ka.acme.invalid";
|
||||
|
||||
KeyPair keypair = KeyPairUtils.createKeyPair(2048);
|
||||
|
||||
X509Certificate cert = CertificateUtils.createTlsSni02Certificate(keypair, sanA, sanB);
|
||||
|
||||
Instant now = Instant.now();
|
||||
Instant end = now.plus(Duration.ofDays(8));
|
||||
|
||||
assertThat(cert, not(nullValue()));
|
||||
assertThat(cert.getNotAfter(), is(greaterThan(Date.from(now))));
|
||||
assertThat(cert.getNotAfter(), is(lessThan(Date.from(end))));
|
||||
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(Date.from(now))));
|
||||
assertThat(cert.getSubjectX500Principal().getName(), is("CN=acme.invalid"));
|
||||
assertThat(getSANs(cert), containsInAnyOrder(sanA, sanB));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if {@link CertificateUtils#readCSR(InputStream)} reads an identical CSR.
|
||||
*/
|
||||
|
|
|
@ -10,6 +10,3 @@ The ACME specifications define these standard challenges:
|
|||
|
||||
* [http-01](./http-01.html)
|
||||
* [dns-01](./dns-01.html)
|
||||
* [tls-sni-01](./tls-sni-01.html)
|
||||
* [tls-sni-02](./tls-sni-02.html)
|
||||
* [oob-01](./oob-01.html)
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# oob-01 Challenge
|
||||
|
||||
> **NOTE:** `oob-01` challenge has been removed in ACMEv2.
|
||||
|
||||
The `oob-01` challenge is an "out of band" challenge that is used when there is no automatic way of validating ownership of a domain. The client is instead required to perform actions outside of the ACME protocol.
|
||||
|
||||
`OutOfBand01Challenge` implements this challenge. Its `getValidationUrl()` method returns a URL that refers to a web page with further instructions about the actions to be taken.
|
||||
|
||||
The challenge must be triggered before the URL is opened in a browser.
|
||||
|
||||
Due to the nature of this challenge, it may take a considerable amount of time until its state changes to `VALID`.
|
|
@ -1,44 +0,0 @@
|
|||
# tls-sni-01 Challenge
|
||||
|
||||
> **SECURITY:** [This challenge is vulnerable in shared hosting environments](https://community.letsencrypt.org/t/2018-01-09-issue-with-tls-sni-01-and-shared-hosting-infrastructure/49996), and is going to be removed from the ACME specs. _Let's Encrypt_ does not offer this challenge to the general public any more.
|
||||
|
||||
With the `tls-sni-01` challenge, you prove to the CA that you are able to control the web server of the domain to be authorized, by letting it respond to a SNI request with a specific self-signed cert.
|
||||
|
||||
`TlsSni01Challenge` provides a subject:
|
||||
|
||||
```java
|
||||
TlsSni01Challenge challenge = auth.findChallenge(TlsSni01Challenge.TYPE);
|
||||
|
||||
String subject = challenge.getSubject();
|
||||
```
|
||||
|
||||
The `subject` is basically a domain name formed like in this example:
|
||||
|
||||
```
|
||||
30c452b9bd088cdbc2c4094947025d7c.7364ea602ac325a1b55ceaae024fbe29.acme.invalid
|
||||
```
|
||||
|
||||
You need to create a self-signed certificate with the subject set as _Subject Alternative Name_. After that, configure your web server so it will use this certificate on a SNI request to the `subject`.
|
||||
|
||||
The `TlsSni01Challenge` class does not generate a self-signed certificate, as it would require _Bouncy Castle_. However, there is a utility method in the _acme4j-utils_ module for this use case:
|
||||
|
||||
```java
|
||||
KeyPair sniKeyPair = KeyPairUtils.createKeyPair(2048);
|
||||
X509Certificate cert = CertificateUtils.createTlsSniCertificate(sniKeyPair, subject);
|
||||
```
|
||||
|
||||
Now use `cert` and `sniKeyPair` to let your web server respond to a SNI request to `subject`.
|
||||
|
||||
The challenge is completed when the CA was able to send the SNI request and get the correct certificate in return.
|
||||
|
||||
Note that the request is sent to port 443 only. There is no way to choose a different port, for security reasons. This is a limitation of the ACME protocol, not of _acme4j_.
|
||||
|
||||
This shell command line may be helpful to test your web server configuration:
|
||||
|
||||
```shell
|
||||
echo QUIT | \
|
||||
openssl s_client -servername $subject -connect $server_ip:443 | \
|
||||
openssl x509 -text -noout
|
||||
```
|
||||
|
||||
It should return a certificate with `subject` set as `X509v3 Subject Alternative Name`.
|
|
@ -1,46 +0,0 @@
|
|||
# tls-sni-02 Challenge
|
||||
|
||||
> **SECURITY:** [This challenge is vulnerable in shared hosting environments](https://community.letsencrypt.org/t/2018-01-09-issue-with-tls-sni-01-and-shared-hosting-infrastructure/49996), and is going to be removed from the ACME specs.
|
||||
|
||||
With the `tls-sni-02` challenge, you prove to the CA that you are able to control the web server of the domain to be authorized, by letting it respond to a SNI request with a specific self-signed cert.
|
||||
|
||||
`TlsSni02Challenge` provides a subject and a key-authorization domain:
|
||||
|
||||
```java
|
||||
TlsSni02Challenge challenge = auth.findChallenge(TlsSni02Challenge.TYPE);
|
||||
|
||||
String subject = challenge.getSubject(); // SAN-A
|
||||
String sanB = challenge.getSanB(); // SAN-B
|
||||
```
|
||||
|
||||
`subject` and `sanB` are basically domain names formed like in this example:
|
||||
|
||||
```
|
||||
5bf0b9908ed73bc53ed3327afa52f76b.0a4bea00520f0753f42abe0bb39e3ea8.token.acme.invalid
|
||||
14e2350a04434f93c2e0b6012968d99d.ed459b6a7a019d9695609b8514f9d63d.ka.acme.invalid
|
||||
```
|
||||
|
||||
You need to create a self-signed certificate with both `subject` and `sanB` set as _Subject Alternative Name_. After that, configure your web server so it will use this certificate on a SNI request to `subject`.
|
||||
|
||||
The `TlsSni02Challenge` class does not generate a self-signed certificate, as it would require _Bouncy Castle_. However, there is a utility method in the _acme4j-utils_ module for this use case:
|
||||
|
||||
```java
|
||||
KeyPair sniKeyPair = KeyPairUtils.createKeyPair(2048);
|
||||
X509Certificate cert = CertificateUtils.createTlsSni02Certificate(sniKeyPair, subject, sanB);
|
||||
```
|
||||
|
||||
Now use `cert` and `sniKeyPair` to let your web server respond to SNI requests to `subject`. The CA is not allowed to reveal `sanB`, so it will not perform SNI requests to that domain.
|
||||
|
||||
The challenge is completed when the CA was able to send the SNI request and get the correct certificate in return.
|
||||
|
||||
Note that the request is sent to port 443 only. There is no way to choose a different port, for security reasons. This is a limitation of the ACME protocol, not of _acme4j_.
|
||||
|
||||
This shell command line may be helpful to test your web server configuration:
|
||||
|
||||
```shell
|
||||
echo QUIT | \
|
||||
openssl s_client -servername $subject -connect $server_ip:443 | \
|
||||
openssl x509 -text -noout
|
||||
```
|
||||
|
||||
It should return a certificate with both `subject` and `sanB` set as `X509v3 Subject Alternative Name`.
|
|
@ -40,9 +40,6 @@
|
|||
<item name="Challenges" href="challenge/index.html">
|
||||
<item name="http-01" href="challenge/http-01.html"/>
|
||||
<item name="dns-01" href="challenge/dns-01.html"/>
|
||||
<item name="tls-sni-01" href="challenge/tls-sni-01.html"/>
|
||||
<item name="tls-sni-02" href="challenge/tls-sni-02.html"/>
|
||||
<item name="oob-01" href="challenge/oob-01.html"/>
|
||||
</item>
|
||||
<item name="CAs" href="ca/index.html">
|
||||
<item name="Let's Encrypt" href="ca/letsencrypt.html"/>
|
||||
|
|
Loading…
Reference in New Issue