You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ne...@apache.org on 2016/12/06 21:13:59 UTC
[10/12] incubator-trafficcontrol git commit: TR - can now opt to use
dns sec signing without jdnssec
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/693ced51/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/keys/ZoneSignerTest.java
----------------------------------------------------------------------
diff --git a/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/keys/ZoneSignerTest.java b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/keys/ZoneSignerTest.java
new file mode 100644
index 0000000..e847991
--- /dev/null
+++ b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/keys/ZoneSignerTest.java
@@ -0,0 +1,188 @@
+package com.comcast.cdn.traffic_control.traffic_router.core.dns.keys;
+
+import com.comcast.cdn.traffic_control.traffic_router.core.IsEqualCollection;
+import com.comcast.cdn.traffic_control.traffic_router.core.dns.DNSKeyPairWrapper;
+import com.comcast.cdn.traffic_control.traffic_router.core.dns.DnsSecKeyPair;
+import com.comcast.cdn.traffic_control.traffic_router.core.dns.DnsSecKeyPairImpl;
+import com.comcast.cdn.traffic_control.traffic_router.core.dns.JDnsSecSigner;
+import com.comcast.cdn.traffic_control.traffic_router.core.dns.ZoneSignerImpl;
+import com.comcast.cdn.traffic_control.traffic_router.secure.Pkcs1;
+import com.verisignlabs.dnssec.security.DnsKeyPair;
+import com.verisignlabs.dnssec.security.JCEDnsSecSigner;
+import com.verisignlabs.dnssec.security.SignUtils;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.xbill.DNS.DSRecord;
+import org.xbill.DNS.Record;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static com.comcast.cdn.traffic_control.traffic_router.core.IsEqualCollection.equalTo;
+import static com.comcast.cdn.traffic_control.traffic_router.core.dns.keys.ZoneTestRecords.keySigningKeyRecord;
+import static com.comcast.cdn.traffic_control.traffic_router.core.dns.keys.ZoneTestRecords.ksk1;
+import static com.comcast.cdn.traffic_control.traffic_router.core.dns.keys.ZoneTestRecords.ksk2;
+import static com.comcast.cdn.traffic_control.traffic_router.core.dns.keys.ZoneTestRecords.origin;
+import static com.comcast.cdn.traffic_control.traffic_router.core.dns.keys.ZoneTestRecords.sep_1_2016;
+import static com.comcast.cdn.traffic_control.traffic_router.core.dns.keys.ZoneTestRecords.sep_1_2026;
+import static com.comcast.cdn.traffic_control.traffic_router.core.dns.keys.ZoneTestRecords.zoneSigningKeyRecord;
+import static com.comcast.cdn.traffic_control.traffic_router.core.dns.keys.ZoneTestRecords.zsk1;
+import static com.comcast.cdn.traffic_control.traffic_router.core.dns.keys.ZoneTestRecords.zsk2;
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toList;
+import static org.junit.Assert.assertThat;
+import static org.xbill.DNS.DSRecord.SHA256_DIGEST_ID;
+
+public class ZoneSignerTest {
+
+ private DnsKeyPair kskPair1;
+ private DnsKeyPair kskPair2;
+ private DnsKeyPair zskPair1;
+ private DnsKeyPair zskPair2;
+ private JSONObject ksk1Json;
+ private JSONObject ksk2Json;
+ private JSONObject zsk1Json;
+ private JSONObject zsk2Json;
+ private final long dsTtl = 1234000L;
+
+ @Before
+ public void before() throws Exception {
+ ZoneTestRecords.generateZoneRecords(false);
+ SigningData.recreateData();
+
+ kskPair1 = new DnsKeyPair(keySigningKeyRecord, ksk1.getPrivate());
+ kskPair2 = new DnsKeyPair(keySigningKeyRecord, ksk2.getPrivate());
+ zskPair1 = new DnsKeyPair(zoneSigningKeyRecord, zsk1.getPrivate());
+ zskPair2 = new DnsKeyPair(zoneSigningKeyRecord, zsk2.getPrivate());
+
+ // Data like we would fetch from traffic ops api for dnsseckeys.json
+ ksk1Json = new JSONObject("{" +
+ "'inceptionDate':1475280000," +
+ "'effectiveDate': 1475280000," +
+ "'expirationDate': 1790812800," +
+ "'ttl': 3600," +
+ "'name':'example.com.'," +
+ "'private': '" + SigningData.ksk1Private + "'," +
+ "'public': '" + SigningData.keyDnsKeyRecord + "'" +
+ "}");
+
+
+ ksk2Json = new JSONObject("{" +
+ "'inceptionDate':1475280000," +
+ "'effectiveDate': 1475280000," +
+ "'expirationDate': 1790812800," +
+ "'ttl': 3600," +
+ "'name':'example.com.'," +
+ "'private': '" + SigningData.ksk2Private + "'," +
+ "'public': '" + SigningData.keyDnsKeyRecord + "'" +
+ "}");
+
+ zsk1Json = new JSONObject("{" +
+ "'inceptionDate':1475280000," +
+ "'effectiveDate': 1475280000," +
+ "'expirationDate': 1790812800," +
+ "'ttl': 31556952," +
+ "'name':'example.com.'," +
+ "'private': '" + SigningData.zsk1Private + "'," +
+ "'public': '" + SigningData.zoneDnsKeyRecord + "'" +
+ "}");
+
+ zsk2Json = new JSONObject("{" +
+ "'inceptionDate':1475280000," +
+ "'effectiveDate': 1475280000," +
+ "'expirationDate': 1790812800," +
+ "'ttl': 315569520," +
+ "'name':'example.com.'," +
+ "'private': '" + SigningData.zsk2Private + "'," +
+ "'public': '" + SigningData.zoneDnsKeyRecord + "'" +
+ "}");
+ }
+
+ @Test
+ public void itCanReproduceResultsDirectlyFromJdnsSec() throws Exception {
+ List<DnsKeyPair> kskPairs = new ArrayList<>(asList(kskPair1, kskPair2));
+ List<DnsKeyPair> zskPairs = new ArrayList<>(asList(zskPair1, zskPair2));
+
+ JCEDnsSecSigner signer = new JCEDnsSecSigner(false);
+
+ final List<Record> signedRecords = signer.signZone(origin, ZoneTestRecords.records,
+ kskPairs, zskPairs, sep_1_2016, sep_1_2026, true, SHA256_DIGEST_ID);
+
+ assertThat(signedRecords, equalTo(SigningData.signedList));
+ assertThat(ZoneTestRecords.records, equalTo(SigningData.postZoneList));
+ }
+
+ @Test
+ public void itReturnsSameResults() throws Exception {
+ DNSKeyPairWrapper ksk1Wrapper = new DNSKeyPairWrapper(ksk1Json, 1234);
+ ksk1Wrapper.setPrivate(new Pkcs1(SigningData.ksk1Private).getPrivateKey());
+
+ assertThat(ksk1Wrapper.getDNSKEYRecord(), equalTo(kskPair1.getDNSKEYRecord()));
+
+ DNSKeyPairWrapper ksk2Wrapper = new DNSKeyPairWrapper(ksk2Json, 1234);
+ ksk2Wrapper.setPrivate(new Pkcs1(SigningData.ksk2Private).getPrivateKey());
+
+ assertThat(ksk2Wrapper.getDNSKEYRecord(), equalTo(kskPair2.getDNSKEYRecord()));
+
+ List<DnsSecKeyPair> kskWrapperPairs = new ArrayList<>(asList(ksk1Wrapper, ksk2Wrapper));
+
+ DNSKeyPairWrapper zsk1Wrapper = new DNSKeyPairWrapper(zsk1Json, 1234);
+ zsk1Wrapper.setPrivate(new Pkcs1(SigningData.zsk1Private).getPrivateKey());
+
+ assertThat(zsk1Wrapper.getDNSKEYRecord(), equalTo(zskPair1.getDNSKEYRecord()));
+
+ DNSKeyPairWrapper zsk2Wrapper = new DNSKeyPairWrapper(zsk2Json, 1234);
+ zsk2Wrapper.setPrivate(new Pkcs1(SigningData.zsk2Private).getPrivateKey());
+
+ assertThat(zsk2Wrapper.getDNSKEYRecord(), equalTo(zskPair2.getDNSKEYRecord()));
+
+ List<DnsSecKeyPair> zskWrapperPairs = new ArrayList<>(asList(zsk1Wrapper, zsk2Wrapper));
+
+ final List<Record> signedRecords2 = new JDnsSecSigner().signZone(origin, ZoneTestRecords.records,
+ kskWrapperPairs, zskWrapperPairs, sep_1_2016, sep_1_2026, true, SHA256_DIGEST_ID);
+
+ assertThat(signedRecords2, equalTo(SigningData.signedList));
+ assertThat(ZoneTestRecords.records, equalTo(SigningData.postZoneList));
+ }
+
+ @Test
+ public void itReturnsTheSameResultsWithoutJDnsSec() throws Exception {
+ DnsSecKeyPair kskPair1 = new DnsSecKeyPairImpl(ksk1Json, 1234);
+ DnsSecKeyPair kskPair2 = new DnsSecKeyPairImpl(ksk2Json, 1234);
+ DnsSecKeyPair zskPair1 = new DnsSecKeyPairImpl(zsk1Json, 1234);
+ DnsSecKeyPair zskPair2 = new DnsSecKeyPairImpl(zsk2Json, 1234);
+
+ List<DnsSecKeyPair> kskPairs = new ArrayList<>(asList(kskPair1, kskPair2));
+ List<DnsSecKeyPair> zskPairs = new ArrayList<>(asList(zskPair1, zskPair2));
+
+ final List<Record> signedRecords = new ZoneSignerImpl().signZone(origin, ZoneTestRecords.records,
+ kskPairs, zskPairs, sep_1_2016, sep_1_2026, true, SHA256_DIGEST_ID);
+
+ assertThat("Signed records not equal", signedRecords, equalTo(SigningData.signedList));
+ assertThat("Post Zone Records not equal", ZoneTestRecords.records, equalTo(SigningData.postZoneList));
+ }
+
+ @Test
+ public void itCanReproduceDSRecordsFromJdnsSec() throws Exception {
+ List<DnsKeyPair> kskPairs = new ArrayList<>(asList(kskPair1, kskPair2));
+ List<DSRecord> dsRecords = kskPairs.stream()
+ .map(dnsKeyPair -> SignUtils.calculateDSRecord(dnsKeyPair.getDNSKEYRecord(), SHA256_DIGEST_ID, dsTtl))
+ .collect(toList());
+
+ assertThat(dsRecords, IsEqualCollection.equalTo(SigningData.dsRecordList));
+ }
+
+ @Test
+ public void itReturnsSameDSRecords() throws Exception {
+ DnsSecKeyPair kskPair1 = new DnsSecKeyPairImpl(ksk1Json, 1234);
+ DnsSecKeyPair kskPair2 = new DnsSecKeyPairImpl(ksk2Json, 1234);
+
+ List<DSRecord> dsRecords = Stream.of(kskPair1, kskPair2)
+ .map(dnsSecKeyPair -> new ZoneSignerImpl().calculateDSRecord(kskPair1.getDNSKEYRecord(), SHA256_DIGEST_ID, 54321L))
+ .collect(toList());
+ assertThat(dsRecords, IsEqualCollection.equalTo(SigningData.dsRecordList));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/693ced51/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/keys/ZoneTestRecords.java
----------------------------------------------------------------------
diff --git a/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/keys/ZoneTestRecords.java b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/keys/ZoneTestRecords.java
new file mode 100644
index 0000000..6ddf554
--- /dev/null
+++ b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/keys/ZoneTestRecords.java
@@ -0,0 +1,128 @@
+package com.comcast.cdn.traffic_control.traffic_router.core.dns.keys;
+
+import com.comcast.cdn.traffic_control.traffic_router.secure.Pkcs1;
+import org.xbill.DNS.AAAARecord;
+import org.xbill.DNS.ARecord;
+import org.xbill.DNS.CNAMERecord;
+import org.xbill.DNS.DClass;
+import org.xbill.DNS.DNSKEYRecord;
+import org.xbill.DNS.NSRecord;
+import org.xbill.DNS.Name;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.SOARecord;
+
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import static org.xbill.DNS.DNSKEYRecord.Flags.SEP_KEY;
+import static org.xbill.DNS.DNSKEYRecord.Flags.ZONE_KEY;
+import static org.xbill.DNS.DNSKEYRecord.Protocol.DNSSEC;
+import static org.xbill.DNS.DNSSEC.Algorithm.RSASHA1;
+
+public class ZoneTestRecords {
+ static List<Record> records;
+
+ static Date start;
+ static Date expiration;
+ static Name origin;
+ static Date sep_1_2016 = new Date(1472688000000L);
+ static Date sep_1_2026 = new Date(1788220800000L);
+ static DNSKEYRecord zoneSigningKeyRecord;
+ static DNSKEYRecord keySigningKeyRecord;
+
+ static KeyPair ksk1;
+ static KeyPair zsk1;
+ static KeyPair ksk2;
+ static KeyPair zsk2;
+
+ static List<KeyPair> generateKeyPairs() throws Exception {
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(2048, SecureRandom.getInstance("SHA1PRNG","SUN"));
+ List<KeyPair> keyPairs = new ArrayList<>();
+ keyPairs.add(keyPairGenerator.generateKeyPair());
+ keyPairs.add(keyPairGenerator.generateKeyPair());
+ keyPairs.add(keyPairGenerator.generateKeyPair());
+ keyPairs.add(keyPairGenerator.generateKeyPair());
+ return keyPairs;
+ }
+
+ private static KeyPair recreateKeyPair(String publicKey, String privateKey) throws Exception {
+ Pkcs1 pkcs1 = new Pkcs1(privateKey, publicKey);
+
+ PrivateKey privateKeyCopy = pkcs1.getPrivateKey();
+ PublicKey publicKeyCopy = pkcs1.getPublicKey();
+
+ return new KeyPair(publicKeyCopy, privateKeyCopy);
+ }
+
+ static List<Record> generateZoneRecords(boolean makeNewKeyPairs) throws Exception {
+ start = new Date(System.currentTimeMillis() - (24 * 3600 * 1000));
+ expiration = new Date(System.currentTimeMillis() + (7 * 24 * 3600 * 1000));
+
+ origin = new Name("example.com.");
+
+ Duration tenYears = Duration.ofDays(3650);
+ Duration oneDay = Duration.ofDays(1);
+ Duration threeDays = Duration.ofDays(3);
+ Duration threeWeeks = Duration.ofDays(21);
+
+ long oneHour = 3600;
+ Name nameServer1 = new Name("ns1.example.com.");
+ Name nameServer2 = new Name("ns2.example.com.");
+
+ Name adminEmail = new Name("admin.example.com.");
+
+ Name webServer = new Name("www.example.com.");
+ Name ftpServer = new Name("ftp.example.com.");
+
+ Name webMirror = new Name("mirror.www.example.com.");
+ Name ftpMirror = new Name("mirror.ftp.example.com.");
+
+ records = new ArrayList<>(Arrays.asList(
+ new AAAARecord(webServer, DClass.IN, threeDays.getSeconds(), Inet6Address.getByName("2001:db8::5:6:7:8")),
+ new AAAARecord(ftpServer, DClass.IN, threeDays.getSeconds(), Inet6Address.getByName("2001:db8::12:34:56:78")),
+ new NSRecord(origin, DClass.IN, tenYears.getSeconds(), nameServer1),
+ new NSRecord(origin, DClass.IN, tenYears.getSeconds(), nameServer2),
+ new ARecord(webServer, DClass.IN, threeWeeks.getSeconds(), InetAddress.getByAddress(new byte[] {11, 22, 33, 44})),
+ new ARecord(webServer, DClass.IN, threeWeeks.getSeconds(), InetAddress.getByAddress(new byte[] {55, 66, 77, 88})),
+ new ARecord(ftpServer, DClass.IN, threeWeeks.getSeconds(), InetAddress.getByAddress(new byte[] {12, 34, 56, 78})),
+ new ARecord(ftpServer, DClass.IN, threeWeeks.getSeconds(), InetAddress.getByAddress(new byte[] {21, 43, 65, 87})),
+ new AAAARecord(webServer, DClass.IN, threeDays.getSeconds(), Inet6Address.getByName("2001:db8::4:3:2:1")),
+ new SOARecord(origin, DClass.IN, tenYears.getSeconds(), nameServer1,
+ adminEmail, 2016091400L, oneDay.getSeconds(), oneHour, threeWeeks.getSeconds(), threeDays.getSeconds()),
+ new AAAARecord(ftpServer, DClass.IN, threeDays.getSeconds(), Inet6Address.getByName("2001:db8::21:43:65:87")),
+ new CNAMERecord(webMirror, DClass.IN, tenYears.getSeconds(), webServer),
+ new CNAMERecord(ftpMirror, DClass.IN, tenYears.getSeconds(), ftpServer)
+ ));
+
+ if (makeNewKeyPairs) {
+ List<KeyPair> keyPairs = generateKeyPairs();
+ ksk1 = keyPairs.get(0);
+ zsk1 = keyPairs.get(1);
+ ksk2 = keyPairs.get(2);
+ zsk2 = keyPairs.get(3);
+ } else {
+ ksk1 = recreateKeyPair(SigningData.ksk1Public, SigningData.ksk1Private);
+ zsk1 = recreateKeyPair(SigningData.zsk1Public, SigningData.zsk1Private);
+ ksk2 = recreateKeyPair(SigningData.ksk2Public, SigningData.ksk2Private);
+ zsk2 = recreateKeyPair(SigningData.zsk2Public, SigningData.zsk2Private);
+ }
+
+ zoneSigningKeyRecord = new DNSKEYRecord(origin, DClass.IN, 31556952L,
+ ZONE_KEY, DNSSEC, RSASHA1, zsk1.getPublic().getEncoded());
+
+ keySigningKeyRecord = new DNSKEYRecord(origin, DClass.IN, 315569520L,
+ ZONE_KEY | SEP_KEY, DNSSEC, RSASHA1, ksk1.getPublic().getEncoded());
+ return records;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/693ced51/traffic_router/shared/build/pmd/ruleset.xml
----------------------------------------------------------------------
diff --git a/traffic_router/shared/build/pmd/ruleset.xml b/traffic_router/shared/build/pmd/ruleset.xml
index dcbc791..807dc0f 100644
--- a/traffic_router/shared/build/pmd/ruleset.xml
+++ b/traffic_router/shared/build/pmd/ruleset.xml
@@ -80,7 +80,6 @@
<rule ref="rulesets/java/codesize.xml/NcssTypeCount" />
<rule ref="rulesets/java/codesize.xml/NcssConstructorCount" />
- <rule ref="rulesets/java/controversial.xml/DontImportSun" />
<rule ref="rulesets/java/controversial.xml/SuspiciousOctalEscape" />
<rule ref="rulesets/java/controversial.xml/AvoidUsingNativeCode" />
<rule ref="rulesets/java/controversial.xml/AvoidAccessibilityAlteration" />
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/693ced51/traffic_router/shared/pom.xml
----------------------------------------------------------------------
diff --git a/traffic_router/shared/pom.xml b/traffic_router/shared/pom.xml
index b7c7b23..2d27390 100644
--- a/traffic_router/shared/pom.xml
+++ b/traffic_router/shared/pom.xml
@@ -59,6 +59,11 @@ under the License.
<dependencies>
<dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>${log4j.version}</version>
+ </dependency>
+ <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.0</version>
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/693ced51/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs.java
----------------------------------------------------------------------
diff --git a/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs.java b/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs.java
new file mode 100644
index 0000000..e69e039
--- /dev/null
+++ b/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs.java
@@ -0,0 +1,84 @@
+/*
+ *
+ * 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 com.comcast.cdn.traffic_control.traffic_router.secure;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.KeySpec;
+
+@SuppressWarnings("PMD.AbstractNaming")
+public abstract class Pkcs {
+ private final String data;
+ private final PrivateKey privateKey;
+ private PublicKey publicKey;
+ private KeySpec keySpec;
+ private KeySpec publicKeySpec;
+
+ public Pkcs(final String data) throws IOException, GeneralSecurityException {
+ this.data = data;
+ keySpec = toKeySpec(data);
+ privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
+ }
+
+ public Pkcs(final String privateData, final String publicData) throws IOException, GeneralSecurityException {
+ this.data = privateData;
+ keySpec = toKeySpec(data);
+ privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
+ publicKeySpec = toKeySpec(publicData);
+ publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public KeySpec getKeySpec() {
+ return keySpec;
+ }
+
+ public KeySpec getPublicKeySpec() {
+ return publicKeySpec;
+ }
+
+ public void setKeySpec(final KeySpec keySpec) {
+ this.keySpec = keySpec;
+ }
+
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
+
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ public abstract String getHeader();
+
+ public abstract String getFooter();
+
+ private String stripHeaderAndFooter(final String data) {
+ return data.replaceAll(getHeader(), "").replaceAll(getFooter(), "").replaceAll("\\s", "");
+ }
+
+ protected abstract KeySpec decodeKeySpec(final String data) throws IOException, GeneralSecurityException;
+
+ private KeySpec toKeySpec(final String data) throws IOException, GeneralSecurityException {
+ return decodeKeySpec(stripHeaderAndFooter(data));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/693ced51/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs1.java
----------------------------------------------------------------------
diff --git a/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs1.java b/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs1.java
new file mode 100644
index 0000000..ea50705
--- /dev/null
+++ b/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs1.java
@@ -0,0 +1,89 @@
+/*
+ *
+ * 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 com.comcast.cdn.traffic_control.traffic_router.secure;
+
+import sun.security.util.DerInputStream;
+import sun.security.util.DerValue;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.spec.KeySpec;
+import java.security.spec.RSAMultiPrimePrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Base64;
+
+public class Pkcs1 extends Pkcs {
+
+ // https://tools.ietf.org/html/rfc3447#appendix-A.1.1
+
+ static public final String HEADER = "-----BEGIN RSA PRIVATE KEY-----";
+ static public final String FOOTER = "-----END RSA PRIVATE KEY-----";
+ static final int PRIVATE_SEQUENCE_LENGTH = 9;
+ static final int PUBLIC_SEQUENCE_LENGTH = 2;
+
+ public Pkcs1(final String data) throws IOException, GeneralSecurityException {
+ super(data);
+ }
+
+ public Pkcs1(final String privateData, final String publicData) throws IOException, GeneralSecurityException {
+ super(privateData,publicData);
+ }
+
+ @Override
+ public String getHeader() {
+ return HEADER;
+ }
+
+ @Override
+ public String getFooter() {
+ return FOOTER;
+ }
+
+ @Override
+ protected KeySpec decodeKeySpec(final String data) throws IOException, GeneralSecurityException {
+ final String pemData = data.replaceAll(HEADER, "").replaceAll(FOOTER, "").replaceAll("\\s", "");
+
+ final DerInputStream derInputStream = new DerInputStream(Base64.getDecoder().decode(pemData));
+ final DerValue[] derSequence = derInputStream.getSequence(0);
+
+ if (derSequence.length != PUBLIC_SEQUENCE_LENGTH && derSequence.length != PRIVATE_SEQUENCE_LENGTH) {
+ throw new GeneralSecurityException("Invalid PKCS1 key! Missing Key Data, incorrect number of DER values for either public or private key");
+ }
+
+ if (derSequence.length == PUBLIC_SEQUENCE_LENGTH) {
+ final BigInteger n = derSequence[0].getBigInteger();
+ final BigInteger e = derSequence[1].getBigInteger();
+ return new RSAPublicKeySpec(n,e);
+ }
+
+ // man 3 rsa
+ // -- or --
+ // http://linux.die.net/man/3/rsa
+
+ // We don't need the version data at derSequence[0]
+ final BigInteger n = derSequence[1].getBigInteger();
+ final BigInteger e = derSequence[2].getBigInteger();
+ final BigInteger d = derSequence[3].getBigInteger();
+ final BigInteger p = derSequence[4].getBigInteger();
+ final BigInteger q = derSequence[5].getBigInteger();
+ final BigInteger dmp1 = derSequence[6].getBigInteger();
+ final BigInteger dmq1 = derSequence[7].getBigInteger();
+ final BigInteger iqmp = derSequence[8].getBigInteger();
+
+ return new RSAMultiPrimePrivateCrtKeySpec(n, e, d, p, q, dmp1, dmq1, iqmp, null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/693ced51/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs8.java
----------------------------------------------------------------------
diff --git a/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs8.java b/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs8.java
new file mode 100644
index 0000000..5a2f764
--- /dev/null
+++ b/traffic_router/shared/src/main/java/com/comcast/cdn/traffic_control/traffic_router/secure/Pkcs8.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * 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 com.comcast.cdn.traffic_control.traffic_router.secure;
+
+import org.apache.log4j.Logger;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+
+public class Pkcs8 extends Pkcs {
+ private static final Logger LOGGER = Logger.getLogger(Pkcs8.class);
+ public static final String HEADER = "-----BEGIN PRIVATE KEY-----";
+ public static final String FOOTER = "-----END PRIVATE KEY-----";
+
+ public Pkcs8(final String data) throws IOException, GeneralSecurityException {
+ super(data);
+ }
+
+ @Override
+ public String getHeader() {
+ return HEADER;
+ }
+
+ @Override
+ public String getFooter() {
+ return FOOTER;
+ }
+
+ @Override
+ protected KeySpec decodeKeySpec(final String data) throws IOException, GeneralSecurityException {
+ try {
+ return new PKCS8EncodedKeySpec(Base64.getDecoder().decode((data.getBytes())));
+ } catch (Exception e) {
+ LOGGER.error("Failed to create PKCS8 Encoded Key Spec " + e.getClass().getCanonicalName() + ": " + e.getMessage(), e);
+ }
+ return null;
+ }
+}