diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/ProofOfPossession01Challenge.java b/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/ProofOfPossession01Challenge.java deleted file mode 100644 index c24b6c1e..00000000 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/challenge/ProofOfPossession01Challenge.java +++ /dev/null @@ -1,142 +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 java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.KeyPair; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.jose4j.base64url.Base64Url; -import org.jose4j.json.JsonUtil; -import org.jose4j.lang.JoseException; -import org.shredzone.acme4j.Registration; -import org.shredzone.acme4j.exception.AcmeProtocolException; -import org.shredzone.acme4j.util.ClaimBuilder; -import org.shredzone.acme4j.util.ValidationBuilder; - -/** - * Implements the {@value TYPE} challenge. - * - * @author Richard "Shred" Körber - */ -public class ProofOfPossession01Challenge extends GenericChallenge { - private static final long serialVersionUID = 6212440828380185335L; - - protected static final String KEY_CERTS = "certs"; - protected static final String KEY_AUTHORIZATION = "authorization"; - - /** - * Challenge type name: {@value} - */ - public static final String TYPE = "proof-of-possession-01"; - - private Collection certs; - private String validation; - - /** - * Gets the collection of {@link X509Certificate} known by the server. - */ - public Collection getCertificates() { - return certs; - } - - /** - * Authorizes the challenge by signing it with the {@link Registration} of the current - * domain owner. - * - * @param ownerRegistration - * {@link Registration} of the certificate holder - * @param domainKeypair - * {@link KeyPair} matching one of the requested certificates - * @param domains - * Domains to validate - */ - public void authorize(Registration ownerRegistration, KeyPair domainKeypair, String... domains) { - importValidation(new ValidationBuilder() - .domains(domains) - .sign(ownerRegistration, domainKeypair)); - } - - /** - * Imports a validation JWS. - * - * @param validation - * JWS of the validation - * @see ValidationBuilder - */ - public void importValidation(String validation) { - try { - Map json = JsonUtil.parseJson(validation); - if (!json.keySet().containsAll(Arrays.asList("header", "payload", "signature"))) { - throw new IllegalArgumentException("not a JWS"); - } - } catch (JoseException ex) { - throw new IllegalArgumentException("invalid JSON", ex); - } - - this.validation = validation; - } - - @Override - public void unmarshall(Map map) { - super.unmarshall(map); - - List certData = get(KEY_CERTS); - if (certData != null) { - try { - CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); - - certs = new ArrayList<>(certData.size()); - for (String c : certData) { - byte[] certDer = Base64Url.decode(c); - try (ByteArrayInputStream in = new ByteArrayInputStream(certDer)) { - certs.add((X509Certificate) certificateFactory.generateCertificate(in)); - } - } - } catch (CertificateException | IOException ex) { - throw new AcmeProtocolException("Invalid certificates", ex); - } - } - } - - @Override - public void respond(ClaimBuilder cb) { - if (validation == null) { - throw new IllegalStateException("not validated"); - } - - super.respond(cb); - - try { - cb.put(KEY_AUTHORIZATION, JsonUtil.parseJson(validation)); - } catch (JoseException ex) { - // should not happen, as the JSON is prevalidated in the setter - throw new AcmeProtocolException("validation: invalid JSON", ex); - } - } - - @Override - protected boolean acceptable(String type) { - return TYPE.equals(type); - } - -} diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeClientProvider.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeClientProvider.java index 56207872..1f135ee0 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeClientProvider.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/AbstractAcmeClientProvider.java @@ -19,7 +19,6 @@ import org.shredzone.acme4j.AcmeClient; import org.shredzone.acme4j.challenge.Challenge; import org.shredzone.acme4j.challenge.Dns01Challenge; import org.shredzone.acme4j.challenge.Http01Challenge; -import org.shredzone.acme4j.challenge.ProofOfPossession01Challenge; import org.shredzone.acme4j.challenge.TlsSni01Challenge; import org.shredzone.acme4j.challenge.TlsSni02Challenge; import org.shredzone.acme4j.connector.Connection; @@ -73,7 +72,6 @@ public abstract class AbstractAcmeClientProvider implements AcmeClientProvider { case Dns01Challenge.TYPE: return new Dns01Challenge(); case TlsSni01Challenge.TYPE: return new TlsSni01Challenge(); case TlsSni02Challenge.TYPE: return new TlsSni02Challenge(); - case ProofOfPossession01Challenge.TYPE: return new ProofOfPossession01Challenge(); case Http01Challenge.TYPE: return new Http01Challenge(); default: return null; } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/util/ValidationBuilder.java b/acme4j-client/src/main/java/org/shredzone/acme4j/util/ValidationBuilder.java deleted file mode 100644 index 7d1dfb6c..00000000 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/util/ValidationBuilder.java +++ /dev/null @@ -1,129 +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.util; - -import java.security.KeyPair; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.jose4j.jwk.PublicJsonWebKey; -import org.jose4j.jws.JsonWebSignature; -import org.jose4j.lang.JoseException; -import org.shredzone.acme4j.Registration; -import org.shredzone.acme4j.challenge.ProofOfPossession01Challenge; -import org.shredzone.acme4j.exception.AcmeProtocolException; - -/** - * Generates a validation string for {@link ProofOfPossession01Challenge}. - * - * @author Richard "Shred" Körber - */ -public class ValidationBuilder { - - private final List> identifiers = new ArrayList<>(); - - /** - * Adds a domain to the validation. - * - * @param domain - * Domain to be added - * @return {@code this} - */ - public ValidationBuilder domain(String domain) { - if (domain == null || domain.isEmpty()) { - throw new IllegalArgumentException("domain must not be empty or null"); - } - - ClaimBuilder cb = new ClaimBuilder(); - cb.put("type", "dns").put("value", domain); - identifiers.add(cb.toMap()); - return this; - } - - /** - * Adds a collection of domains to the validation. - * - * @param domains - * Domains to be added - * @return {@code this} - */ - public ValidationBuilder domains(Collection domains) { - if (domains == null) { - throw new NullPointerException("domains must not be null"); - } - - for (String d : domains) { - domain(d); - } - return this; - } - - /** - * Adds multiple domains to the validation. - * - * @param domains - * Domains to be added - * @return {@code this} - */ - public ValidationBuilder domains(String... domains) { - return domains(Arrays.asList(domains)); - } - - /** - * Signs with the given {@link KeyPair} and returns a signed JSON Web Signature - * structure that can be used for validation. - * - * @param registration - * {@link Registration} of the current domain owner - * @param keypair - * One of the {@link KeyPair} requested by the challenge - * @return JWS validation object - */ - public String sign(Registration registration, KeyPair keypair) { - if (registration == null) { - throw new NullPointerException("registration must not be null"); - } - if (keypair == null) { - throw new NullPointerException("keypair must not be null"); - } - - try { - ClaimBuilder claims = new ClaimBuilder(); - claims.put("type", ProofOfPossession01Challenge.TYPE); - claims.array("identifiers", identifiers.toArray()); - claims.putKey("accountKey", registration.getKeyPair().getPublic()); - - final PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(keypair.getPublic()); - - JsonWebSignature jws = new JsonWebSignature(); - jws.setPayload(claims.toString()); - jws.getHeaders().setJwkHeaderValue("jwk", jwk); - jws.setAlgorithmHeaderValue(SignatureUtils.keyAlgorithm(jwk)); - jws.setKey(keypair.getPrivate()); - jws.sign(); - - ClaimBuilder auth = new ClaimBuilder(); - auth.put("header", jws.getHeaders().getFullHeaderAsJsonString()); - auth.put("payload", jws.getEncodedPayload()); - auth.put("signature", jws.getEncodedSignature()); - return auth.toString(); - } catch (JoseException ex) { - throw new AcmeProtocolException("Failed to sign", ex); - } - } - -} diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java index 1567412d..a9384ef4 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/AuthorizationTest.java @@ -32,7 +32,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.ProofOfPossession01Challenge; import org.shredzone.acme4j.challenge.TlsSni02Challenge; /** @@ -42,6 +41,8 @@ import org.shredzone.acme4j.challenge.TlsSni02Challenge; */ public class AuthorizationTest { + private static final String SNAILMAIL_TYPE = "snail-01"; // a non-existent challenge + private Authorization authorization; /** @@ -101,8 +102,8 @@ public class AuthorizationTest { */ @Test public void testFindChallenge() { - // ProofOfPossesionChallenge is not available at all - Challenge c1 = authorization.findChallenge(ProofOfPossession01Challenge.TYPE); + // A snail mail challenge is not available at all + Challenge c1 = authorization.findChallenge(SNAILMAIL_TYPE); assertThat(c1, is(nullValue())); // HttpChallenge is available as standalone challenge @@ -140,7 +141,7 @@ public class AuthorizationTest { instanceOf(TlsSni02Challenge.class))); // Finds smaller combinations as well - Collection c4 = authorization.findCombination(Dns01Challenge.TYPE, TlsSni02Challenge.TYPE, ProofOfPossession01Challenge.TYPE); + Collection c4 = authorization.findCombination(Dns01Challenge.TYPE, TlsSni02Challenge.TYPE, SNAILMAIL_TYPE); assertThat(c4, hasSize(2)); assertThat(c4, contains(instanceOf(Dns01Challenge.class), instanceOf(TlsSni02Challenge.class))); @@ -155,7 +156,7 @@ public class AuthorizationTest { assertThat(c6, is(nullValue())); // Does not find challenges that have not been provided - Collection c7 = authorization.findCombination(ProofOfPossession01Challenge.TYPE); + Collection c7 = authorization.findCombination(SNAILMAIL_TYPE); assertThat(c7, is(nullValue())); } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ProofOfPossessionChallengeTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ProofOfPossessionChallengeTest.java deleted file mode 100644 index 2ffb9ce8..00000000 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/challenge/ProofOfPossessionChallengeTest.java +++ /dev/null @@ -1,100 +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.*; -import static org.junit.Assert.*; -import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; - -import java.io.IOException; -import java.security.KeyPair; -import java.security.cert.X509Certificate; - -import org.junit.Test; -import org.shredzone.acme4j.Registration; -import org.shredzone.acme4j.Status; -import org.shredzone.acme4j.util.ClaimBuilder; -import org.shredzone.acme4j.util.TestUtils; -import org.shredzone.acme4j.util.ValidationBuilder; - -/** - * Unit tests for {@link ProofOfPossession01Challenge}. - * - * @author Richard "Shred" Körber - */ -public class ProofOfPossessionChallengeTest { - - /** - * Test that {@link ProofOfPossession01Challenge} generates a correct authorization key. - */ - @Test - public void testProofOfPossessionChallenge() throws IOException { - X509Certificate cert = TestUtils.createCertificate(); - KeyPair keypair = TestUtils.createKeyPair(); - Registration reg = new Registration(keypair); - KeyPair domainKeyPair = TestUtils.createDomainKeyPair(); - - ProofOfPossession01Challenge challenge = new ProofOfPossession01Challenge(); - challenge.unmarshall(TestUtils.getJsonAsMap("proofOfPossessionChallenge")); - - assertThat(challenge.getCertificates(), contains(cert)); - - assertThat(challenge.getType(), is(ProofOfPossession01Challenge.TYPE)); - assertThat(challenge.getStatus(), is(Status.PENDING)); - - try { - challenge.respond(new ClaimBuilder()); - fail("marshall() without previous authorize()"); - } catch (IllegalStateException ex) { - // expected - } - - challenge.authorize(reg, domainKeyPair, "example.org"); - - ClaimBuilder cb = new ClaimBuilder(); - challenge.respond(cb); - - assertThat(cb.toString(), sameJSONAs("{\"type\"=\"" - + ProofOfPossession01Challenge.TYPE + "\",\"authorization\"=" - + new ValidationBuilder().domain("example.org").sign(reg, domainKeyPair) - + "}")); - } - - /** - * Test that {@link ProofOfPossession01Challenge#importValidation(String)} works - * correctly. - */ - @Test - public void testImportValidation() throws IOException { - KeyPair keypair = TestUtils.createKeyPair(); - Registration reg = new Registration(keypair); - KeyPair domainKeyPair = TestUtils.createDomainKeyPair(); - - String validation = new ValidationBuilder() - .domain("example.org") - .sign(reg, domainKeyPair); - - ProofOfPossession01Challenge challenge = new ProofOfPossession01Challenge(); - challenge.unmarshall(TestUtils.getJsonAsMap("proofOfPossessionChallenge")); - challenge.importValidation(validation); - - ClaimBuilder cb = new ClaimBuilder(); - challenge.respond(cb); - - assertThat(cb.toString(), sameJSONAs("{\"type\"=\"" - + ProofOfPossession01Challenge.TYPE + "\",\"authorization\"=" + validation - + "}")); - } - -} diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/provider/AbstractAcmeClientProviderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/provider/AbstractAcmeClientProviderTest.java index b9ac9c61..c4b56422 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/provider/AbstractAcmeClientProviderTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/provider/AbstractAcmeClientProviderTest.java @@ -24,7 +24,6 @@ import org.shredzone.acme4j.AcmeClient; import org.shredzone.acme4j.challenge.Challenge; import org.shredzone.acme4j.challenge.Dns01Challenge; import org.shredzone.acme4j.challenge.Http01Challenge; -import org.shredzone.acme4j.challenge.ProofOfPossession01Challenge; import org.shredzone.acme4j.challenge.TlsSni02Challenge; /** @@ -101,20 +100,16 @@ public class AbstractAcmeClientProviderTest { assertThat(c3, not(nullValue())); assertThat(c3, instanceOf(Dns01Challenge.class)); - Challenge c4 = provider.createChallenge(ProofOfPossession01Challenge.TYPE); + Challenge c4 = provider.createChallenge(org.shredzone.acme4j.challenge.TlsSni01Challenge.TYPE); assertThat(c4, not(nullValue())); - assertThat(c4, instanceOf(ProofOfPossession01Challenge.class)); + assertThat(c4, instanceOf(org.shredzone.acme4j.challenge.TlsSni01Challenge.class)); - Challenge c5 = provider.createChallenge(org.shredzone.acme4j.challenge.TlsSni01Challenge.TYPE); + Challenge c5 = provider.createChallenge(TlsSni02Challenge.TYPE); assertThat(c5, not(nullValue())); - assertThat(c5, instanceOf(org.shredzone.acme4j.challenge.TlsSni01Challenge.class)); + assertThat(c5, instanceOf(TlsSni02Challenge.class)); - Challenge c6 = provider.createChallenge(TlsSni02Challenge.TYPE); - assertThat(c6, not(nullValue())); - assertThat(c6, instanceOf(TlsSni02Challenge.class)); - - Challenge c7 = provider.createChallenge("foobar-01"); - assertThat(c7, is(nullValue())); + Challenge c6 = provider.createChallenge("foobar-01"); + assertThat(c6, is(nullValue())); try { provider.createChallenge(null); diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/util/ValidationBuilderTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/util/ValidationBuilderTest.java deleted file mode 100644 index b25589bf..00000000 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/util/ValidationBuilderTest.java +++ /dev/null @@ -1,90 +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.util; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; -import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; - -import java.io.IOException; -import java.security.KeyPair; -import java.util.Arrays; -import java.util.Map; - -import org.jose4j.base64url.Base64Url; -import org.jose4j.json.JsonUtil; -import org.jose4j.lang.JoseException; -import org.junit.Test; -import org.shredzone.acme4j.Registration; - -/** - * Unit test for {@link ValidationBuilder}. - * - * @author Richard "Shred" Körber - */ -public class ValidationBuilderTest { - - /** - * Test if a correct JWS validation object is generated. - */ - @Test - public void testValidationBuilder() throws IOException, JoseException { - Registration reg = new Registration(TestUtils.createKeyPair()); - KeyPair domainKeyPair = TestUtils.createDomainKeyPair(); - - assertThat(reg.getKeyPair(), not(domainKeyPair)); - - ValidationBuilder vb = new ValidationBuilder(); - vb.domain("abc.de").domain("ef.gh"); - vb.domains("ijk.lm", "no.pq", "rst.uv"); - vb.domains(Arrays.asList("w.x", "y.z")); - String json = vb.sign(reg, domainKeyPair); - - Map data = JsonUtil.parseJson(json); - - String header = (String) data.get("header"); - String payload = Base64Url.decodeToUtf8String((String) data.get("payload")); - String signature = (String) data.get("signature"); - - StringBuilder expectedHeader = new StringBuilder(); - expectedHeader.append('{'); - expectedHeader.append("\"alg\":\"RS256\","); - expectedHeader.append("\"jwk\":{"); - expectedHeader.append("\"kty\":\"").append(TestUtils.D_KTY).append("\","); - expectedHeader.append("\"e\":\"").append(TestUtils.D_E).append("\","); - expectedHeader.append("\"n\":\"").append(TestUtils.D_N).append("\""); - expectedHeader.append("}}"); - - StringBuilder expectedPayload = new StringBuilder(); - expectedPayload.append('{'); - expectedPayload.append("\"type\":\"proof-of-possession-01\","); - expectedPayload.append("\"identifiers\":["); - for (String d : Arrays.asList("abc.de", "ef.gh", "ijk.lm", "no.pq", "rst.uv", "w.x", "y.z")) { - expectedPayload.append("{\"type\":\"dns\",\"value\":\"").append(d).append("\"}"); - if (!"y.z".equals(d)) { - expectedPayload.append(','); - } - } - expectedPayload.append("],\"accountKey\":{"); - expectedPayload.append("\"kty\":\"").append(TestUtils.KTY).append("\","); - expectedPayload.append("\"e\":\"").append(TestUtils.E).append("\","); - expectedPayload.append("\"n\":\"").append(TestUtils.N).append("\""); - expectedPayload.append("}}"); - - assertThat(header, sameJSONAs(expectedHeader.toString()).allowingExtraUnexpectedFields()); - assertThat(payload, sameJSONAs(expectedPayload.toString())); - assertThat(signature, not(isEmptyOrNullString())); - } - -} diff --git a/acme4j-client/src/test/resources/json.properties b/acme4j-client/src/test/resources/json.properties index 92cdf038..d9d949ef 100644 --- a/acme4j-client/src/test/resources/json.properties +++ b/acme4j-client/src/test/resources/json.properties @@ -150,12 +150,6 @@ httpChallenge = \ "token": "rSoI9JpyvFi-ltdnBW0W1DjKstzG7cHixjzcOjwzAEQ" \ } -proofOfPossessionChallenge = \ - { \ - "type": "proof-of-possession-01", \ - "certs": ["MIIDVzCCAj-gAwIBAgIJAM4KDTzb0Y7NMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwHhcNMTUxMjEwMDAxMTA4WhcNMjUxMjA3MDAxMTA4WjBCMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr0g3w4C8xbj_5lzJiDxk0HkEJeZeyruq-0AzOPMigJZ7zxZtX_KUxOIHrQ4qjcFhl0DmQImoM0wESU-kcsjAHCx8E1lgRVlVsMfLAQPHkg5UybqfadzKT3ALcSD-9F9mVIP6liC_6KzLTASmx6zM7j92KTl1ArObZr5mh0jvSNORrMhEC4Byn3-NTxjuHON1rWppCMwpeNNhFzaAig3O8PY8IyaLXNP2Ac5pXn0iW16S-Im9by7751UeW5a7DznmuMEM-WY640ffJDQ4-I64H403uAgvvSu-BGw8SEEZGuBCxoCnG1g6y6OvJyN5TgqFdGosAfm1u-_MP1seoPdpBQIDAQABo1AwTjAdBgNVHQ4EFgQUrie5ZLOrA_HuhW1b_CHjzEvj34swHwYDVR0jBBgwFoAUrie5ZLOrA_HuhW1b_CHjzEvj34swDAYDVR0TBAUwAwEB_zANBgkqhkiG9w0BAQsFAAOCAQEAkSOP0FUgIIUeJTObgXrenHzZpLAkqXi37dgdYuPhNveo3agueP51N7yIoh6YGShiJ73Rvr-lVYTwFXStrLih1Wh3tWvksMxnvocgd7l6USRb5_AgH7eHeFK4DoCAak2hUAcCLDRJN3XMhNLpyJhw7GJxowVIGUlxcW5Asrmh9qflfyMyjripTP3CdHobmNcNHyScjNncKj37m8vomel9acekTtDl2Ci7nLdE-3VqQCXMIfLiF3PO0gGpKei0RuVCSOG6W83zVInCPd_l3aluSR-f_VZlk8KGQ4As4uTQi89j-J1YepzG0ASMZpjVbXeIg5QBAywVxBh5XVTz37KN8A"] \ - } - tlsSniChallenge = \ { \ "type":"tls-sni-01", \ diff --git a/src/site/markdown/challenge/index.md b/src/site/markdown/challenge/index.md index 3ee0cdf3..ef22a8dc 100644 --- a/src/site/markdown/challenge/index.md +++ b/src/site/markdown/challenge/index.md @@ -12,4 +12,3 @@ The ACME specifications define these standard challenges: * [dns-01](./dns-01.html) * [tls-sni-01](./tls-sni-01.html) * [tls-sni-02](./tls-sni-02.html) -* [proof-of-possession-01](./proof-of-possession-01.html) diff --git a/src/site/markdown/challenge/proof-of-possession-01.md b/src/site/markdown/challenge/proof-of-possession-01.md deleted file mode 100644 index a39ac3ef..00000000 --- a/src/site/markdown/challenge/proof-of-possession-01.md +++ /dev/null @@ -1,52 +0,0 @@ -# proof-of-possession-01 Challenge - -With the `proof-of-possession-01` challenge, you prove to the CA that you are able to provide a verification document that is signed with a key that is known to the server. The main purpose of this challenge is to transfer the authorization of a domain to your account. - -The challenge object contains a list of `X509Certificate`s that are already known to the CA: - -```java -ProofOfPossession01Challenge challenge = - auth.findChallenge(ProofOfPossession01Challenge.TYPE); -Collection certificates = challenge.getCertificates(); -``` - -In the next step, the _current owner of the domain_ authorizes the challenge, by signing it with a key pair that corresponds to one of the `certificates`: - -```java -Registration ownerRegistration = ... // Registration of the domain owner -KeyPair domainKeyPair = ... // Key pair matching a certificate -String domain = ... // Domain to authorize - -challenge.authorize(ownerRegistration, domainKeyPair, domain); -``` - -The challenge is completed when the domain is associated with the account of the `ownerRegistration`, and the `domainKeyPair` matches one of the `certificates`. - -## Importing a Validation - -A problem with this challenge is that a third party needs to provide the account and domain key pairs for authorization. - -There is a way to prepare the validation externally, and import a validation document into the challenge in a separate step. The validation document is signed by the domain owner, but does not contain any private keys. - -_acme4j_ offers a `ValidationBuilder` class for generating the validation document: - -```java -Registration ownerRegistration = ... // Registration of the domain owner -KeyPair domainKeyPair = ... // Key pair matching a certificates - -ValidationBuilder vb = new ValidationBuilder(); -vb.domain("example.org"); -String json = vb.sign(ownerRegistration, domainKeyPair); -``` - -This `json` string can be transported (e.g. via email) and then imported into the challenge: - -```java -String json = ... // validation document - -ProofOfPossession01Challenge challenge = - auth.findChallenge(ProofOfPossession01Challenge.TYPE); -challenge.importValidation(json); -``` - -The challenge is authorized now, and is ready to be executed. diff --git a/src/site/markdown/usage/recovery.md b/src/site/markdown/usage/recovery.md index 0aa64441..5483022a 100644 --- a/src/site/markdown/usage/recovery.md +++ b/src/site/markdown/usage/recovery.md @@ -8,7 +8,7 @@ Individual CAs may offer further ways of recovery, which are not part of this do ## Contact-Based Recovery -> **CAUTION**: Contact-Based Recovery is [currently not supported by _Let's Encrypt_](https://github.com/letsencrypt/boulder/issues/432). If you should lose your key pair, you are stuck. All you can do at the moment is to register a new account and then recover your domains by using the [Proof of Possession](../challenge/proof-of-possession.html) challenge in combination with the domain key pairs. +> **CAUTION**: Contact-Based Recovery is [currently not supported by _Let's Encrypt_](https://github.com/letsencrypt/boulder/issues/432). If you should lose your key pair, you are stuck. On this recovery method, the CA contacts the account owner via one of the contact addresses given on account creation. The owner is asked to take some action (e.g. clicking on a link in an email). If it was successful, the account data is transferred to the new account. diff --git a/src/site/site.xml b/src/site/site.xml index f0c9c207..0707b06e 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -41,7 +41,6 @@ -