1
0
mirror of https://github.com/google/nomulus synced 2026-06-09 16:33:02 +00:00

Forbid SHA-1 digests as part of RFC 9904 changes (#3069)

We can't change digest types that are already in the database but that's
fine (since we just store them as integers). But we forbid them as part
of domain creates/updates.
This commit is contained in:
gbrodman
2026-06-01 13:59:19 -04:00
committed by GitHub
parent 0030645b1a
commit dde41078cd
28 changed files with 368 additions and 149 deletions
@@ -23,6 +23,7 @@ import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.intersection;
import static com.google.common.collect.Sets.union;
import static google.registry.bsa.persistence.BsaLabelUtils.isLabelBlocked;
import static google.registry.model.common.FeatureFlag.FeatureName.FORBID_INSECURE_ALGORITHMS_RFC_9904;
import static google.registry.model.domain.Domain.MAX_REGISTRATION_YEARS;
import static google.registry.model.domain.token.AllocationToken.TokenType.REGISTER_BSA;
import static google.registry.model.tld.Tld.TldState.GENERAL_AVAILABILITY;
@@ -73,6 +74,7 @@ import google.registry.model.EppResource;
import google.registry.model.billing.BillingBase.Flag;
import google.registry.model.billing.BillingBase.Reason;
import google.registry.model.billing.BillingRecurrence;
import google.registry.model.common.FeatureFlag;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Create;
import google.registry.model.domain.DomainCommand.CreateOrUpdate;
@@ -341,7 +343,7 @@ public class DomainFlowUtils {
}
ImmutableList<DomainDsData> invalidAlgorithms =
dsData.stream()
.filter(ds -> !validateAlgorithm(ds.getAlgorithm()))
.filter(ds -> algorithmIsInvalid(ds.getAlgorithm()))
.collect(toImmutableList());
if (!invalidAlgorithms.isEmpty()) {
throw new InvalidDsRecordException(
@@ -349,9 +351,16 @@ public class DomainFlowUtils {
"Domain contains DS record(s) with an invalid algorithm wire value: %s",
invalidAlgorithms));
}
boolean forbidInsecureTypes = FeatureFlag.isActiveNow(FORBID_INSECURE_ALGORITHMS_RFC_9904);
ImmutableList<DomainDsData> invalidDigestTypes =
dsData.stream()
.filter(ds -> DigestType.fromWireValue(ds.getDigestType()).isEmpty())
.filter(
ds -> {
Optional<DigestType> digestType = DigestType.fromWireValue(ds.getDigestType());
return digestType
.map(type -> forbidInsecureTypes && !type.isAllowedInRfc9904())
.orElse(true);
})
.collect(toImmutableList());
if (!invalidDigestTypes.isEmpty()) {
throw new InvalidDsRecordException(
@@ -376,14 +385,14 @@ public class DomainFlowUtils {
}
}
public static boolean validateAlgorithm(int alg) {
public static boolean algorithmIsInvalid(int alg) {
if (alg > 255 || alg < 0) {
return false;
return true;
}
// Algorithms that are reserved or unassigned will just return a string representation of their
// integer wire value.
String algorithm = Algorithm.string(alg);
return !algorithm.equals(Integer.toString(alg));
return algorithm.equals(Integer.toString(alg));
}
/** We only allow specifying years in a period. */
@@ -84,7 +84,10 @@ public class FeatureFlag extends ImmutableObject implements Buildable {
INCLUDE_PENDING_DELETE_DATE_FOR_DOMAINS(FeatureStatus.INACTIVE),
/** If we're prohibiting the inclusion of the contact object URI on login. */
PROHIBIT_CONTACT_OBJECTS_ON_LOGIN(FeatureStatus.INACTIVE);
PROHIBIT_CONTACT_OBJECTS_ON_LOGIN(FeatureStatus.INACTIVE),
/** If we're prohibiting insecure algorithms as detailed by RFC 9904. */
FORBID_INSECURE_ALGORITHMS_RFC_9904(FeatureStatus.INACTIVE);
private final FeatureStatus defaultStatus;
@@ -29,21 +29,26 @@ import java.util.Optional;
* https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml
*/
public enum DigestType {
SHA1(1, 20),
SHA256(2, 32),
// Algorithm number 1 is SHA-1 and will be is deliberately NOT SUPPORTED.
// RFC 9904 specifies that this algorithm MUST NOT be used for DNSSEC delegations.
// This prohibition is gated behind a feature flag.
SHA1(1, 20, false),
SHA256(2, 32, true),
// Algorithm number 3 is GOST R 34.11-94 and is deliberately NOT SUPPORTED.
// This algorithm was reviewed by ise-crypto and deemed academically broken (b/207029800).
// In addition, RFC 8624 specifies that this algorithm MUST NOT be used for DNSSEC delegations.
// TODO(sarhabot@): Add note in Cloud DNS code to notify the Registry of any new changes to
// supported digest types.
SHA384(4, 48);
SHA384(4, 48, true);
private final int wireValue;
private final int bytes;
private final boolean allowedInRfc9904;
DigestType(int wireValue, int bytes) {
DigestType(int wireValue, int bytes, boolean allowedInRfc9904) {
this.wireValue = wireValue;
this.bytes = bytes;
this.allowedInRfc9904 = allowedInRfc9904;
}
private static final ImmutableMap<Integer, DigestType> WIRE_VALUE_TO_DIGEST_TYPE =
@@ -63,4 +68,9 @@ public enum DigestType {
public int getBytes() {
return bytes;
}
/** Whether this digest type is supported as of RFC 9904. */
public boolean isAllowedInRfc9904() {
return allowedInRfc9904;
}
}
@@ -46,7 +46,7 @@ record DsRecord(int keyTag, int alg, int digestType, String digest) {
String.format("DS record has an invalid digest length: %s", digest));
}
if (!DomainFlowUtils.validateAlgorithm(alg)) {
if (DomainFlowUtils.algorithmIsInvalid(alg)) {
throw new IllegalArgumentException(
String.format("DS record uses an unrecognized algorithm: %d", alg));
}
@@ -24,6 +24,7 @@ import static google.registry.model.billing.BillingBase.Flag.RESERVED;
import static google.registry.model.billing.BillingBase.Flag.SUNRISE;
import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.NONPREMIUM;
import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPECIFIED;
import static google.registry.model.common.FeatureFlag.FeatureName.FORBID_INSECURE_ALGORITHMS_RFC_9904;
import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS;
import static google.registry.model.domain.token.AllocationToken.TokenType.BULK_PRICING;
import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO;
@@ -150,6 +151,8 @@ import google.registry.model.billing.BillingBase.Reason;
import google.registry.model.billing.BillingBase.RenewalPriceBehavior;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingRecurrence;
import google.registry.model.common.FeatureFlag;
import google.registry.model.common.FeatureFlag.FeatureStatus;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
@@ -794,7 +797,11 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.that(domain)
.hasExactlyDsData(
DomainDsData.create(
12345, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))
12345,
3,
2,
base16()
.decode("D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A"))
.cloneWithDomainRepoId(domain.getRepoId()));
}
@@ -957,6 +964,38 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testFailure_secDnsSha1DigestType() throws Exception {
setEppInput("domain_create_dsdata_sha1.xml");
persistHosts();
DatabaseHelper.persistResource(
new FeatureFlag.Builder()
.setFeatureName(FORBID_INSECURE_ALGORITHMS_RFC_9904)
.setStatusMap(ImmutableSortedMap.of(START_INSTANT, FeatureStatus.ACTIVE))
.build());
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testSuccess_secDnsSha1_flagInactive() throws Exception {
setEppInput("domain_create_dsdata_sha1.xml");
persistHosts();
DatabaseHelper.persistResource(
new FeatureFlag.Builder()
.setFeatureName(FORBID_INSECURE_ALGORITHMS_RFC_9904)
.setStatusMap(ImmutableSortedMap.of(START_INSTANT, FeatureStatus.INACTIVE))
.build());
doSuccessfulTest("tld");
Domain domain = reloadResourceByForeignKey();
assertAboutDomains()
.that(domain)
.hasExactlyDsData(
DomainDsData.create(
12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC49FD46E6C4B45C55D4AC"))
.cloneWithDomainRepoId(domain.getRepoId()));
}
@Test
void testFailure_secDnsInvalidAlgorithm() throws Exception {
setEppInput("domain_create_dsdata_bad_algorithms.xml");
@@ -19,6 +19,7 @@ import static com.google.common.collect.Sets.union;
import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ForeignKeyUtils.loadResource;
import static google.registry.model.common.FeatureFlag.FeatureName.FORBID_INSECURE_ALGORITHMS_RFC_9904;
import static google.registry.model.eppcommon.StatusValue.CLIENT_DELETE_PROHIBITED;
import static google.registry.model.eppcommon.StatusValue.CLIENT_HOLD;
import static google.registry.model.eppcommon.StatusValue.CLIENT_RENEW_PROHIBITED;
@@ -94,6 +95,8 @@ import google.registry.flows.exceptions.ResourceStatusProhibitsOperationExceptio
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingBase.Reason;
import google.registry.model.billing.BillingEvent;
import google.registry.model.common.FeatureFlag;
import google.registry.model.common.FeatureFlag.FeatureStatus;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainHistory;
@@ -115,6 +118,9 @@ import org.junit.jupiter.api.Test;
/** Unit tests for {@link DomainUpdateFlow}. */
class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain> {
private static final String SHA_256_DIGEST =
"D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A";
private static final DomainDsData SOME_DSDATA =
DomainDsData.create(
1,
@@ -125,8 +131,8 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
ImmutableMap.of(
"KEY_TAG", "12346",
"ALG", "3",
"DIGEST_TYPE", "1",
"DIGEST", "A94A8FE5CCB19BA61C4C0873D391E987982FBBD3");
"DIGEST_TYPE", "2",
"DIGEST", SHA_256_DIGEST);
@BeforeEach
void beforeEach() {
@@ -453,18 +459,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
doSecDnsSuccessfulTest(
"domain_update_dsdata_add.xml",
null,
ImmutableSet.of(
DomainDsData.create(
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
ImmutableSet.of(DomainDsData.create(12346, 3, 2, base16().decode(SHA_256_DIGEST))),
ImmutableMap.of(
"KEY_TAG",
"12346",
"ALG",
"3",
"DIGEST_TYPE",
"1",
"DIGEST",
"A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"),
"KEY_TAG", "12346", "ALG", "3", "DIGEST_TYPE", "2", "DIGEST", SHA_256_DIGEST),
true);
}
@@ -474,18 +471,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
"domain_update_dsdata_add.xml",
ImmutableSet.of(SOME_DSDATA),
ImmutableSet.of(
SOME_DSDATA,
DomainDsData.create(
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
SOME_DSDATA, DomainDsData.create(12346, 3, 2, base16().decode(SHA_256_DIGEST))),
ImmutableMap.of(
"KEY_TAG",
"12346",
"ALG",
"3",
"DIGEST_TYPE",
"1",
"DIGEST",
"A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"),
"KEY_TAG", "12346", "ALG", "3", "DIGEST_TYPE", "2", "DIGEST", SHA_256_DIGEST),
true);
}
@@ -660,11 +648,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
union(
commonDsData,
ImmutableSet.of(
DomainDsData.create(
12346,
3,
1,
base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))))),
DomainDsData.create(12346, 3, 2, base16().decode(SHA_256_DIGEST))))),
true);
}
@@ -673,9 +657,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
doSecDnsSuccessfulTest(
"domain_update_dsdata_rem.xml",
ImmutableSet.of(
SOME_DSDATA,
DomainDsData.create(
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
SOME_DSDATA, DomainDsData.create(12346, 3, 2, base16().decode(SHA_256_DIGEST))),
ImmutableSet.of(SOME_DSDATA),
true);
}
@@ -686,9 +668,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
doSecDnsSuccessfulTest(
"domain_update_dsdata_rem_all.xml",
ImmutableSet.of(
SOME_DSDATA,
DomainDsData.create(
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
SOME_DSDATA, DomainDsData.create(12346, 3, 2, base16().decode(SHA_256_DIGEST))),
ImmutableSet.of(),
true);
}
@@ -698,13 +678,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
doSecDnsSuccessfulTest(
"domain_update_dsdata_add_rem.xml",
ImmutableSet.of(
SOME_DSDATA,
DomainDsData.create(
12345, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
SOME_DSDATA, DomainDsData.create(12345, 3, 2, base16().decode(SHA_256_DIGEST))),
ImmutableSet.of(
SOME_DSDATA,
DomainDsData.create(
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
SOME_DSDATA, DomainDsData.create(12346, 3, 2, base16().decode(SHA_256_DIGEST))),
true);
}
@@ -727,20 +703,12 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
union(
commonDsData,
ImmutableSet.of(
DomainDsData.create(
12345,
3,
1,
base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))))),
DomainDsData.create(12345, 3, 2, base16().decode(SHA_256_DIGEST))))),
ImmutableSet.copyOf(
union(
commonDsData,
ImmutableSet.of(
DomainDsData.create(
12346,
3,
1,
base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))))),
DomainDsData.create(12346, 3, 2, base16().decode(SHA_256_DIGEST))))),
true);
}
@@ -915,6 +883,49 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testFailure_secDnsSha1DigestType() throws Exception {
setEppInput(
"domain_update_dsdata_add.xml",
ImmutableMap.of(
"KEY_TAG", "12346",
"ALG", "3",
"DIGEST_TYPE", "1",
"DIGEST", "A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"));
persistResource(DatabaseHelper.newDomain(getUniqueIdFromCommand()));
DatabaseHelper.persistResource(
new FeatureFlag.Builder()
.setFeatureName(FORBID_INSECURE_ALGORITHMS_RFC_9904)
.setStatusMap(ImmutableSortedMap.of(START_INSTANT, FeatureStatus.ACTIVE))
.build());
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testSuccess_secDnsSha1_flagInactive() throws Exception {
setEppInput(
"domain_update_dsdata_add.xml",
ImmutableMap.of(
"KEY_TAG", "12346",
"ALG", "3",
"DIGEST_TYPE", "1",
"DIGEST", "A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"));
persistResource(DatabaseHelper.newDomain(getUniqueIdFromCommand()));
DatabaseHelper.persistResource(
new FeatureFlag.Builder()
.setFeatureName(FORBID_INSECURE_ALGORITHMS_RFC_9904)
.setStatusMap(ImmutableSortedMap.of(START_INSTANT, FeatureStatus.INACTIVE))
.build());
runFlow();
Domain domain = reloadResourceByForeignKey();
assertAboutDomains()
.that(domain)
.hasExactlyDsData(
DomainDsData.create(
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3")));
}
@Test
void testFailure_secDnsMultipleInvalidDigestTypes() throws Exception {
setEppInput("domain_update_dsdata_add.xml", OTHER_DSDATA_TEMPLATE_MAP);
@@ -938,7 +949,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
persistResource(
DatabaseHelper.newDomain(getUniqueIdFromCommand())
.asBuilder()
.setDsData(ImmutableSet.of(DomainDsData.create(1, 2, 1, new byte[] {0, 1, 2})))
.setDsData(ImmutableSet.of(DomainDsData.create(1, 2, 2, new byte[] {0, 1, 2})))
.build());
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
@@ -955,7 +966,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
.asBuilder()
.setDsData(
ImmutableSet.of(
DomainDsData.create(1, 2, 1, new byte[] {0, 1, 2, 3, 4}),
DomainDsData.create(1, 2, 2, new byte[] {0, 1, 2, 3, 4}),
DomainDsData.create(2, 2, 2, new byte[] {5, 6, 7})))
.build());
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
@@ -49,8 +49,8 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
"--period=1",
"--nameservers=ns1.zdns.google,ns2.zdns.google,ns3.zdns.google,ns4.zdns.google",
"--password=2fooBAR",
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 1"
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--ds_records=60485 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"example.tld");
eppVerifier.verifySent("domain_create_complete.xml");
@@ -63,8 +63,8 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
"--period=1",
"--nameservers=NS1.zdns.google,ns2.ZDNS.google,ns3.zdns.gOOglE,ns4.zdns.google",
"--password=2fooBAR",
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 1"
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--ds_records=60485 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"example.tld");
eppVerifier.verifySent("domain_create_complete.xml");
@@ -77,8 +77,8 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
"--period=1",
"--nameservers=ns[1-4].zdns.google",
"--password=2fooBAR",
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 1"
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--ds_records=60485 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"example.tld");
eppVerifier.verifySent("domain_create_complete.xml");
@@ -91,8 +91,8 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
"--period=1",
"--nameservers=NS[1-4].zdns.google",
"--password=2fooBAR",
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 1"
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--ds_records=60485 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"example.tld");
eppVerifier.verifySent("domain_create_complete.xml");
@@ -286,9 +286,7 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
IllegalArgumentException.class,
() ->
runCommandForced(
"--client=NewRegistrar",
"--ds_records=1 2 1 abcd",
"example.tld"));
"--client=NewRegistrar", "--ds_records=1 2 2 abcd", "example.tld"));
assertThat(thrown).hasMessageThat().isEqualTo("DS record has an invalid digest length: ABCD");
}
@@ -0,0 +1,48 @@
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link DigestType}. */
class DigestTypeTest {
@Test
void testFromWireValue_sha1_returnsSha1() {
assertThat(DigestType.fromWireValue(1)).hasValue(DigestType.SHA1);
}
@Test
void testFromWireValue_sha256_returnsSha256() {
assertThat(DigestType.fromWireValue(2)).hasValue(DigestType.SHA256);
}
@Test
void testFromWireValue_gost_returnsEmpty() {
assertThat(DigestType.fromWireValue(3)).isEmpty();
}
@Test
void testFromWireValue_sha384_returnsSha384() {
assertThat(DigestType.fromWireValue(4)).hasValue(DigestType.SHA384);
}
@Test
void testFromWireValue_invalid_returnsEmpty() {
assertThat(DigestType.fromWireValue(5)).isEmpty();
}
}
@@ -79,7 +79,7 @@ class UniformRapidSuspensionCommandTest
runCommandForced(
"--domain_name=evil.tld",
"--hosts=urs1.example.com,urs2.example.com",
"--dsdata=1 1 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--dsdata=1 1 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--renew_one_year=false");
eppVerifier
.expectRegistrarId("CharlestonRoad")
@@ -107,7 +107,7 @@ class UniformRapidSuspensionCommandTest
runCommandForced(
"--domain_name=evil.tld",
"--hosts=urs1.example.com,urs2.example.com",
"--dsdata=1 1 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--dsdata=1 1 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--renew_one_year=false");
eppVerifier
.expectRegistrarId("CharlestonRoad")
@@ -179,7 +179,7 @@ class UniformRapidSuspensionCommandTest
runCommandForced(
"--domain_name=evil.tld",
"--hosts=urs1.example.com,urs2.example.com",
"--dsdata=1 1 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--dsdata=1 1 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--renew_one_year=false");
eppVerifier
.expectRegistrarId("CharlestonRoad")
@@ -198,7 +198,7 @@ class UniformRapidSuspensionCommandTest
runCommandForced(
"--domain_name=evil.tld",
"--hosts=URS[1-2].example.com",
"--dsdata=1 1 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--dsdata=1 1 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--renew_one_year=false");
eppVerifier
.expectRegistrarId("CharlestonRoad")
@@ -76,10 +76,11 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
"--add_nameservers=ns1.zdns.google,ns2.zdns.google",
"--add_statuses=serverDeleteProhibited",
"--add_ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4"
+ " 5 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
+ " 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--remove_nameservers=ns3.zdns.google,ns4.zdns.google",
"--remove_statuses=serverHold",
"--remove_ds_records=7 8 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3,6 5 4"
"--remove_ds_records=7 8 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A,6 5 4"
+ " 768412320F7B0AA5812FCE428DC4706B3CAE50E02A64CAA16A782249BFE8EFC4B7EF1CCB126255D196047DFEDF17A0A9",
"--password=2fooBAR",
"example.tld");
@@ -93,10 +94,11 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
"--add_nameservers=NS[1-2].zdns.google",
"--add_statuses=serverDeleteProhibited",
"--add_ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4"
+ " 5 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
+ " 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--remove_nameservers=ns[3-4].zdns.google",
"--remove_statuses=serverHold",
"--remove_ds_records=7 8 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3,6 5 4"
"--remove_ds_records=7 8 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A,6 5 4"
+ " 768412320F7B0AA5812FCE428DC4706B3CAE50E02A64CAA16A782249BFE8EFC4B7EF1CCB126255D196047DFEDF17A0A9",
"--password=2fooBAR",
"example.tld");
@@ -112,10 +114,11 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
"--add_nameservers=ns1.zdns.google,ns2.zdns.google",
"--add_statuses=serverDeleteProhibited",
"--add_ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4"
+ " 5 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
+ " 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--remove_nameservers=ns[3-4].zdns.google",
"--remove_statuses=serverHold",
"--remove_ds_records=7 8 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3,6 5 4"
"--remove_ds_records=7 8 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A,6 5 4"
+ " 768412320F7B0AA5812FCE428DC4706B3CAE50E02A64CAA16A782249BFE8EFC4B7EF1CCB126255D196047DFEDF17A0A9",
"--password=2fooBAR",
"example.tld",
@@ -163,7 +166,7 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
"--add_nameservers=ns2.zdns.google,ns3.zdns.google",
"--add_statuses=serverDeleteProhibited",
"--add_ds_records=1 2 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A,4"
+ " 5 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
+ " 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"example.tld");
eppVerifier.verifySent("domain_update_add.xml");
}
@@ -174,7 +177,8 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
"--client=NewRegistrar",
"--remove_nameservers=ns4.zdns.google",
"--remove_statuses=serverHold",
"--remove_ds_records=7 8 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3,6 5 4"
"--remove_ds_records=7 8 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A,6 5 4"
+ " 768412320F7B0AA5812FCE428DC4706B3CAE50E02A64CAA16A782249BFE8EFC4B7EF1CCB126255D196047DFEDF17A0A9",
"example.tld");
eppVerifier.verifySent("domain_update_remove.xml");
@@ -230,8 +234,8 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
void testSuccess_setDsRecords() throws Exception {
runCommandForced(
"--client=NewRegistrar",
"--ds_records=1 2 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A,4 5 1"
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--ds_records=1 2 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A,4 5 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"example.tld");
eppVerifier.verifySent("domain_update_set_ds_records.xml");
}
@@ -240,8 +244,8 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
void testSuccess_setDsRecords_withUnneededClear() throws Exception {
runCommandForced(
"--client=NewRegistrar",
"--ds_records=1 2 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A,4 5 1"
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--ds_records=1 2 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A,4 5 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--clear_ds_records",
"example.tld");
eppVerifier.verifySent("domain_update_set_ds_records.xml");
@@ -538,9 +542,7 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
IllegalArgumentException.class,
() ->
runCommandForced(
"--client=NewRegistrar",
"--ds_records=1 2 1 abcd",
"example.tld"));
"--client=NewRegistrar", "--ds_records=1 2 2 abcd", "example.tld"));
assertThat(thrown).hasMessageThat().isEqualTo("DS record has an invalid digest length: ABCD");
}
@@ -554,7 +556,8 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
"--client=NewRegistrar",
"--add_ds_records=1 2 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--ds_records=4 5 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--ds_records=4 5 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"example.tld"));
assertThat(thrown)
.hasMessageThat()
@@ -571,8 +574,10 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
() ->
runCommandForced(
"--client=NewRegistrar",
"--remove_ds_records=7 8 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--ds_records=4 5 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--remove_ds_records=7 8 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--ds_records=4 5 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"example.tld"));
assertThat(thrown)
.hasMessageThat()
@@ -608,7 +613,8 @@ class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomainCommand
() ->
runCommandForced(
"--client=NewRegistrar",
"--remove_ds_records=7 8 1 A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
"--remove_ds_records=7 8 2"
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
"--clear_ds_records",
"example.tld"));
assertThat(thrown)
@@ -22,50 +22,50 @@
<secDNS:dsData>
<secDNS:keyTag>12345</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>12346</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>12347</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>12348</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>12349</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>12350</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>12351</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>12352</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:create>
</extension>
@@ -22,8 +22,8 @@
<secDNS:dsData>
<secDNS:keyTag>12345</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:create>
</extension>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:ns>
<domain:hostObj>ns1.example.net</domain:hostObj>
<domain:hostObj>ns2.example.net</domain:hostObj>
</domain:ns>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<extension>
<secDNS:create
xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
<secDNS:dsData>
<secDNS:keyTag>12345</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>49FD46E6C4B45C55D4AC49FD46E6C4B45C55D4AC</secDNS:digest>
</secDNS:dsData>
</secDNS:create>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>
@@ -15,16 +15,16 @@
<secDNS:dsData>
<secDNS:keyTag>12345</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:rem>
<secDNS:add>
<secDNS:dsData>
<secDNS:keyTag>12346</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
@@ -15,8 +15,8 @@
<secDNS:dsData>
<secDNS:keyTag>12346</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:rem>
</secDNS:update>
@@ -15,8 +15,8 @@
<secDNS:dsData>
<secDNS:keyTag>12346</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
@@ -15,8 +15,8 @@
<secDNS:dsData>
<secDNS:keyTag>12346</secDNS:keyTag>
<secDNS:alg>3</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:rem>
</secDNS:update>
@@ -28,8 +28,8 @@
<secDNS:dsData>
<secDNS:keyTag>4</secDNS:keyTag>
<secDNS:alg>5</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>60485</secDNS:keyTag>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:period unit="y">1</domain:period>
<domain:ns>
<domain:hostObj>ns1.zdns.google</domain:hostObj>
<domain:hostObj>ns2.zdns.google</domain:hostObj>
<domain:hostObj>ns3.zdns.google</domain:hostObj>
<domain:hostObj>ns4.zdns.google</domain:hostObj>
</domain:ns>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<extension>
<secDNS:create xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
<secDNS:dsData>
<secDNS:keyTag>1</secDNS:keyTag>
<secDNS:alg>2</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
</secDNS:dsData>
</secDNS:create>
</extension>
<clTRID>RegistryTool</clTRID>
</command>
</epp>
@@ -26,8 +26,8 @@
<secDNS:dsData>
<secDNS:keyTag>4</secDNS:keyTag>
<secDNS:alg>5</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
@@ -32,8 +32,8 @@
<secDNS:dsData>
<secDNS:keyTag>7</secDNS:keyTag>
<secDNS:alg>8</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>6</secDNS:keyTag>
@@ -52,8 +52,8 @@
<secDNS:dsData>
<secDNS:keyTag>4</secDNS:keyTag>
<secDNS:alg>5</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
@@ -32,8 +32,8 @@
<secDNS:dsData>
<secDNS:keyTag>7</secDNS:keyTag>
<secDNS:alg>8</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>6</secDNS:keyTag>
@@ -52,8 +52,8 @@
<secDNS:dsData>
<secDNS:keyTag>4</secDNS:keyTag>
<secDNS:alg>5</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
@@ -19,8 +19,8 @@
<secDNS:dsData>
<secDNS:keyTag>7</secDNS:keyTag>
<secDNS:alg>8</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
<secDNS:dsData>
<secDNS:keyTag>6</secDNS:keyTag>
@@ -22,8 +22,8 @@
<secDNS:dsData>
<secDNS:keyTag>4</secDNS:keyTag>
<secDNS:alg>5</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<update>
<domain:update
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:add>
<domain:ns>
<domain:hostObj>ns2.zdns.google</domain:hostObj>
<domain:hostObj>ns3.zdns.google</domain:hostObj>
</domain:ns>
<domain:status s="serverDeleteProhibited"/>
</domain:add>
</domain:update>
</update>
<extension>
<secDNS:update xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
<secDNS:add>
<secDNS:dsData>
<secDNS:keyTag>1</secDNS:keyTag>
<secDNS:alg>2</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
</extension>
<clTRID>RegistryTool</clTRID>
</command>
</epp>
@@ -30,8 +30,8 @@
<secDNS:dsData>
<secDNS:keyTag>1</secDNS:keyTag>
<secDNS:alg>1</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
@@ -31,8 +31,8 @@
<secDNS:dsData>
<secDNS:keyTag>1</secDNS:keyTag>
<secDNS:alg>1</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>
@@ -29,8 +29,8 @@
<secDNS:dsData>
<secDNS:keyTag>1</secDNS:keyTag>
<secDNS:alg>1</secDNS:alg>
<secDNS:digestType>1</secDNS:digestType>
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
<secDNS:digestType>2</secDNS:digestType>
<secDNS:digest>D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A</secDNS:digest>
</secDNS:dsData>
</secDNS:add>
</secDNS:update>