() {
@Override
public X509EncodedKeySpec parseResult(byte[] bytes) throws IOException {
@@ -215,8 +286,28 @@ public class Pems {
}
/**
- * Executes {@link Pems#publicKeySpec(InputSupplier)} on the string which
- * contains an encoded public key in PEM format.
+ * Decode PKCS#1 encoded public key into RSAPublicKeySpec.
+ *
+ * Keys here can be in two different formats. They can have the algorithm encoded, or they can have only the modulus
+ * and the public exponent.
+ *
+ * The latter is not a valid PEM encoded file, but it is a valid DER encoded RSA key, so this method should also
+ * support it.
+ *
+ * @param keyBytes
+ * Encoded PKCS#1 rsa key.
+ */
+ private static enum DecodeRSAPublicKeySpec implements PemProcessor.ResultParser {
+ INSTANCE;
+ @Override
+ public KeySpec parseResult(byte[] bytes) throws IOException {
+ return decodeRSAPublicKey(bytes);
+ }
+ }
+
+ /**
+ * Executes {@link Pems#publicKeySpec(InputSupplier)} on the string which contains an encoded public key in PEM
+ * format.
*
* @param pem
* public key in pem encoded format.
@@ -227,8 +318,7 @@ public class Pems {
}
/**
- * Returns the {@link X509EncodedKeySpec} that is pem encoded in the
- * supplier.
+ * Returns the {@link X509EncodedKeySpec} that is pem encoded in the supplier.
*
* @param supplier
* the input stream factory
@@ -242,19 +332,17 @@ public class Pems {
*/
public static X509Certificate x509Certificate(InputSupplier extends InputStream> supplier,
@Nullable CertificateFactory certFactory) throws IOException, CertificateException {
- final CertificateFactory finalCertFactory = certFactory != null ? certFactory : CertificateFactory
- .getInstance("X.509");
+ final CertificateFactory certs = certFactory != null ? certFactory : CertificateFactory.getInstance("X.509");
try {
return fromPem(
supplier,
- new PemProcessor(ImmutableMap.> of(
- CERTIFICATE_X509_MARKER, new ResultParser() {
+ new PemProcessor(ImmutableMap.> of(
+ CERTIFICATE_X509_MARKER, new PemProcessor.ResultParser() {
@Override
public X509Certificate parseResult(byte[] bytes) throws IOException {
try {
- return (X509Certificate) finalCertFactory.generateCertificate(new ByteArrayInputStream(
- bytes));
+ return (X509Certificate) certs.generateCertificate(new ByteArrayInputStream(bytes));
} catch (CertificateException e) {
throw new RuntimeException(e);
}
@@ -262,16 +350,14 @@ public class Pems {
})));
} catch (RuntimeException e) {
- if (e.getCause() != null && e.getCause() instanceof CertificateException) {
- throw (CertificateException) e.getCause();
- }
+ propagateIfInstanceOf(e.getCause(), CertificateException.class);
throw e;
}
}
/**
- * Executes {@link Pems#x509Certificate(InputSupplier, CertificateFactory)}
- * on the string which contains an X.509 certificate in PEM format.
+ * Executes {@link Pems#x509Certificate(InputSupplier, CertificateFactory)} on the string which contains an X.509
+ * certificate in PEM format.
*
* @param pem
* certificate in pem encoded format.
@@ -297,12 +383,6 @@ public class Pems {
/**
* encodes the {@link PublicKey} to PEM format.
- *
- * @param cert
- * what to encode
- * @return the PEM encoded public key
- * @throws IOException
- * @throws CertificateEncodingException
*/
public static String pem(PublicKey key) {
String marker = key instanceof RSAPublicKey ? PUBLIC_PKCS1_MARKER : PUBLIC_X509_MARKER;
@@ -310,49 +390,23 @@ public class Pems {
}
/**
- * encodes the {@link PrivateKey} to PEM format. Note
- *
- * @param cert
- * what to encode
- * @return the PEM encoded private key
- * @throws IOException
- * @throws CertificateEncodingException
+ * encodes the {@link PrivateKey} to PEM format.
*/
- // TODO: understand why pem isn't passing SshKeysTest.testCanGenerate where
- // keys are checked to match.
public static String pem(PrivateKey key) {
String marker = key instanceof RSAPrivateCrtKey ? PRIVATE_PKCS1_MARKER : PRIVATE_PKCS8_MARKER;
- return pem(key instanceof RSAPrivateCrtKey ? getEncoded(RSAPrivateCrtKey.class.cast(key)) : key.getEncoded(),
- marker);
- }
-
- // TODO find a way to do this without using bouncycastle
- public static byte[] getEncoded(RSAPrivateCrtKey key) {
- RSAPrivateKey keyStruct = new RSAPrivateKey(key.getModulus(), key.getPublicExponent(),
- key.getPrivateExponent(), key.getPrimeP(), key.getPrimeQ(), key.getPrimeExponentP(),
- key.getPrimeExponentQ(), key.getCrtCoefficient());
-
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- ASN1OutputStream aOut = new ASN1OutputStream(bOut);
-
- try {
- aOut.writeObject(keyStruct);
- aOut.close();
- } catch (IOException e) {
- throw propagate(e);
- }
-
- return bOut.toByteArray();
+ return pem(key instanceof RSAPrivateCrtKey ? encode(RSAPrivateCrtKey.class.cast(key)) : key.getEncoded(), marker);
}
private static String pem(byte[] key, String marker) {
return pem(key, marker, 64);
}
- static String pem(byte[] key, String marker, int length) {
- return new StringBuilder(marker + "\n")
- .append(Joiner.on('\n').join(Splitter.fixedLength(length).split(CryptoStreams.base64(key))))
- .append("\n" + marker.replace("BEGIN", "END") + "\n").toString().trim();
+ private static String pem(byte[] encoded, String marker, int length) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(marker).append('\n');
+ builder.append(on('\n').join(fixedLength(64).split(base64().encode(encoded)))).append('\n');
+ builder.append(marker.replace("BEGIN", "END")).append('\n');
+ return builder.toString();
}
}
diff --git a/core/src/main/java/org/jclouds/crypto/SshKeys.java b/core/src/main/java/org/jclouds/crypto/SshKeys.java
index 2d830930d8..e5a81c7677 100644
--- a/core/src/main/java/org/jclouds/crypto/SshKeys.java
+++ b/core/src/main/java/org/jclouds/crypto/SshKeys.java
@@ -20,7 +20,6 @@ package org.jclouds.crypto;
import static com.google.common.base.Joiner.on;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Splitter.fixedLength;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.get;
@@ -29,6 +28,7 @@ import static com.google.common.io.BaseEncoding.base64;
import static org.jclouds.crypto.CryptoStreams.base64;
import static org.jclouds.crypto.CryptoStreams.hex;
import static org.jclouds.crypto.CryptoStreams.md5;
+import static org.jclouds.crypto.Pems.pem;
import static org.jclouds.crypto.Pems.privateKeySpec;
import static org.jclouds.util.Strings2.toStringAndClose;
@@ -50,9 +50,6 @@ import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Map;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.jclouds.io.InputSuppliers;
import com.google.common.annotations.Beta;
@@ -153,7 +150,7 @@ public class SshKeys {
KeyPair pair = generateRsaKeyPair(generator, rand);
Builder builder = ImmutableMap.builder();
builder.put("public", encodeAsOpenSSH(RSAPublicKey.class.cast(pair.getPublic())));
- builder.put("private", encodeAsPem(RSAPrivateKey.class.cast(pair.getPrivate())));
+ builder.put("private", pem(RSAPrivateKey.class.cast(pair.getPrivate())));
return builder.build();
}
@@ -162,25 +159,6 @@ public class SshKeys {
return "ssh-rsa " + base64(keyBlob);
}
- public static String encodeAsPem(RSAPrivateKey key) {
- String type = "RSA PRIVATE KEY";
- byte[] encoded = asn1Encode(checkNotNull(key, type));
- StringBuilder builder = new StringBuilder();
- builder.append("-----BEGIN ").append(type).append("-----").append('\n');
- builder.append(on('\n').join(fixedLength(64).split(base64().encode(encoded)))).append('\n');
- builder.append("-----END ").append(type).append("-----").append('\n');
- return builder.toString();
- }
-
- private static byte[] asn1Encode(RSAPrivateKey key) {
- try {
- PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) ASN1Primitive.fromByteArray(key.getEncoded()));
- return info.parsePrivateKey().toASN1Primitive().getEncoded();
- } catch (IOException e) {
- throw propagate(e);
- }
- }
-
/**
* @param privateKeyPEM
* RSA private key in PEM format
diff --git a/core/src/main/java/org/jclouds/crypto/pem/PKCS1EncodedPrivateKeySpec.java b/core/src/main/java/org/jclouds/crypto/pem/PKCS1EncodedPrivateKeySpec.java
deleted file mode 100644
index e496d92b0c..0000000000
--- a/core/src/main/java/org/jclouds/crypto/pem/PKCS1EncodedPrivateKeySpec.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. jclouds licenses this file
- * to you 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 org.jclouds.crypto.pem;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPrivateKeySpec;
-
-import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
-
-/**
- * PKCS#1 encoded private key spec.
- *
- * @author Ignasi Barrera
- */
-public class PKCS1EncodedPrivateKeySpec {
-
- private RSAPrivateCrtKeySpec keySpec;
-
- /**
- * Create a PKCS#1 keyspec from DER encoded buffer
- *
- * @param keyBytes
- * DER encoded octet stream
- * @throws IOException
- */
- public PKCS1EncodedPrivateKeySpec(final byte[] keyBytes) {
- decode(keyBytes);
- }
-
- /**
- * Get the key spec that JCE understands.
- *
- * @return CRT keyspec defined by JCE
- */
- public RSAPrivateKeySpec getKeySpec() {
- return keySpec;
- }
-
- /**
- * Decode PKCS#1 encoded private key into RSAPrivateCrtKeySpec.
- *
- * @param keyBytes
- * Encoded PKCS#1 rsa key.
- */
- private void decode(final byte[] keyBytes) {
- RSAPrivateKey rsa = RSAPrivateKey.getInstance(keyBytes);
-
- BigInteger mod = rsa.getModulus();
- BigInteger pubExp = rsa.getPublicExponent();
- BigInteger privExp = rsa.getPrivateExponent();
- BigInteger p1 = rsa.getPrime1();
- BigInteger p2 = rsa.getPrime2();
- BigInteger exp1 = rsa.getExponent1();
- BigInteger exp2 = rsa.getExponent2();
- BigInteger crtCoef = rsa.getCoefficient();
-
- keySpec = new RSAPrivateCrtKeySpec(mod, pubExp, privExp, p1, p2, exp1, exp2, crtCoef);
- }
-}
diff --git a/core/src/main/java/org/jclouds/crypto/pem/PKCS1EncodedPublicKeySpec.java b/core/src/main/java/org/jclouds/crypto/pem/PKCS1EncodedPublicKeySpec.java
deleted file mode 100644
index 47ac084718..0000000000
--- a/core/src/main/java/org/jclouds/crypto/pem/PKCS1EncodedPublicKeySpec.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. jclouds licenses this file
- * to you 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 org.jclouds.crypto.pem;
-
-import java.io.IOException;
-import java.security.spec.RSAPublicKeySpec;
-
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.pkcs.RSAPublicKey;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-
-/**
- * PKCS#1 encoded public key spec.
- *
- * @author Adrian Cole
- */
-public class PKCS1EncodedPublicKeySpec {
-
- private RSAPublicKeySpec keySpec;
-
- /**
- * Create a PKCS#1 keyspec from DER encoded buffer
- *
- * @param keyBytes
- * DER encoded octet stream
- * @throws IOException
- */
- public PKCS1EncodedPublicKeySpec(final byte[] keyBytes) throws IOException {
- decode(keyBytes);
- }
-
- /**
- * Get the key spec that JCE understands.
- *
- * @return CRT keyspec defined by JCE
- */
- public RSAPublicKeySpec getKeySpec() {
- return keySpec;
- }
-
- /**
- * Decode PKCS#1 encoded public key into RSAPublicKeySpec.
- *
- * Keys here can be in two different formats. They can have the algorithm
- * encoded, or they can have only the modulus and the public exponent.
- *
- * The latter is not a valid PEM encoded file, but it is a valid DER encoded
- * RSA key, so this method should also support it.
- *
- * @param keyBytes
- * Encoded PKCS#1 rsa key.
- */
- private void decode(final byte[] keyBytes) throws IOException {
- RSAPublicKey pks = null;
- ASN1Sequence seq = ASN1Sequence.getInstance(keyBytes);
- try {
- // Try to parse the public key normally. If the algorithm is not
- // present in the encoded key, an IllegalArgumentException will be
- // raised.
- SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(seq);
- pks = RSAPublicKey.getInstance(info.parsePublicKey());
- } catch (IllegalArgumentException ex) {
- // If the algorithm is not found in the encoded key, try to extract
- // just the modulus and the public exponent to build the public key.
- pks = RSAPublicKey.getInstance(seq);
- }
- keySpec = new RSAPublicKeySpec(pks.getModulus(), pks.getPublicExponent());
- }
-}
diff --git a/core/src/test/java/org/jclouds/crypto/PemsTest.java b/core/src/test/java/org/jclouds/crypto/PemsTest.java
index 492f9febfe..070deeaa06 100644
--- a/core/src/test/java/org/jclouds/crypto/PemsTest.java
+++ b/core/src/test/java/org/jclouds/crypto/PemsTest.java
@@ -56,12 +56,12 @@ public class PemsTest {
private static final String CERTIFICATE = "-----BEGIN CERTIFICATE-----\nMIIClzCCAgCgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMCVVMx\nEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFjAUBgNVBAoM\nDU9wc2NvZGUsIEluYy4xHDAaBgNVBAsME0NlcnRpZmljYXRlIFNlcnZpY2UxMjAw\nBgNVBAMMKW9wc2NvZGUuY29tL2VtYWlsQWRkcmVzcz1hdXRoQG9wc2NvZGUuY29t\nMB4XDTEwMDczMDIwNDEzMFoXDTIwMDcyNzIwNDEzMFowADCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAMm9mSSahptCikfvJ30CTbEnfhfbVzTFewnznFuo\n7KrPBGYIlUdPYQ9SGDo+GKjNKiTjZYMoOMUVnsHUhu0Ez49ZSaVQInWvbF8tvpM8\nmoGQNQJtDmXG6m+YaHiA4HF/ng2u/bNLtA6Jo3HzvRCobxywc/szPt0Kj0ZD1fJ2\nE237Ph41c8zlOg9QdF0d/iD2WZdgJ1rNndKoZ0rR3A1L50VUND+PNmMDfVYHHjmb\naT89AwihCeU8eUk7m/JNP87f1QDB0Gny0rkDC3drOGS7jmabTf/7gLE5sYq3qnd+\n8/vGU3QWyfCxKSfogl7kn5uWlIe4sOqMb06GNgC+d/oytlECAwEAATANBgkqhkiG\n9w0BAQUFAAOBgQBftzSZxstWw60GqRTDNN/F2GnrdtnKBoXzHww3r6jtGEylYq20\n5KfKpEx+sPX0gyZuYJiXC2CkEjImAluWKcdN9ZF6VD541sheAjbiaU7q7ZsztTxF\nWUH2tCvHeDXYKPKek3QzL7bYpUhLnCN/XxEv6ibeMDwtI7f5qpk2Aspzcw==\n-----END CERTIFICATE-----\n";
- @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "^Invalid PEM file: no parsers for marker -----BEGIN FOO PRIVATE KEY----- .*")
+ @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "^Invalid PEM: no parsers for marker -----BEGIN FOO PRIVATE KEY----- .*")
public void testPrivateKeySpecFromPemWithInvalidMarker() throws IOException {
Pems.privateKeySpec(Payloads.newStringPayload(INVALID_PRIVATE_KEY));
}
- @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "^Invalid PEM file: no parsers for marker -----BEGIN FOO PUBLIC KEY----- .*")
+ @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "^Invalid PEM: no parsers for marker -----BEGIN FOO PUBLIC KEY----- .*")
public void testPublicKeySpecFromPemWithInvalidMarker() throws IOException {
Pems.publicKeySpec(Payloads.newStringPayload(INVALID_PUBLIC_KEY));
}
@@ -91,21 +91,21 @@ public class PemsTest {
RSAPrivateCrtKey key = (RSAPrivateCrtKey) KeyFactory.getInstance("RSA").generatePrivate(
Pems.privateKeySpec(Payloads.newStringPayload(PRIVATE_KEY)));
String encoded = Pems.pem(key);
- assertEquals(encoded, PRIVATE_KEY.replaceAll("\n", "\n").trim());
+ assertEquals(encoded, PRIVATE_KEY.replaceAll("\n", "\n"));
}
@Test
public void testRSAPublicKeySpecPem() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
String encoded = Pems.pem(KeyFactory.getInstance("RSA").generatePublic(
Pems.publicKeySpec(Payloads.newStringPayload(PUBLIC_KEY))));
- assertEquals(encoded, PUBLIC_KEY.replaceAll("PUBLIC", "RSA PUBLIC").replaceAll("\n", "\n").trim());
+ assertEquals(encoded, PUBLIC_KEY.replaceAll("PUBLIC", "RSA PUBLIC").replaceAll("\n", "\n"));
}
@Test
public void testRSAPKCS1PublicKeySpecPem() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
String encoded = Pems.pem(KeyFactory.getInstance("RSA").generatePublic(
Pems.publicKeySpec(Payloads.newStringPayload(PUBLIC_KEY_PKCS1))));
- assertEquals(encoded, PUBLIC_KEY_PKCS1.replaceAll("\n", "\n").trim());
+ assertEquals(encoded, PUBLIC_KEY_PKCS1.replaceAll("\n", "\n"));
}
@Test
@@ -132,7 +132,7 @@ public class PemsTest {
public void testX509CertificatePem() throws IOException, CertificateException {
String encoded = Pems.pem(Pems.x509Certificate(Payloads.newStringPayload(CERTIFICATE),
CertificateFactory.getInstance("X.509")));
- assertEquals(encoded, CERTIFICATE.replaceAll("\n", "\n").trim());
+ assertEquals(encoded, CERTIFICATE.replaceAll("\n", "\n"));
}
}
diff --git a/drivers/bouncycastle/pom.xml b/drivers/bouncycastle/pom.xml
index 7728df32bf..0c0cb165eb 100644
--- a/drivers/bouncycastle/pom.xml
+++ b/drivers/bouncycastle/pom.xml
@@ -64,6 +64,7 @@
org.bouncycastle
bcprov-jdk15on
+ 1.47