From 023b549e20ea45cc2062f3cb24c18b6c7d2b7e0a Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Fri, 28 Dec 2012 23:11:42 -0800 Subject: [PATCH] Remove explicit dependency on bouncycastle for PEM parsing --- core/pom.xml | 5 - .../main/java/org/jclouds/crypto/Pems.java | 264 +++++++++++------- .../main/java/org/jclouds/crypto/SshKeys.java | 26 +- .../pem/PKCS1EncodedPrivateKeySpec.java | 78 ------ .../crypto/pem/PKCS1EncodedPublicKeySpec.java | 86 ------ .../java/org/jclouds/crypto/PemsTest.java | 12 +- drivers/bouncycastle/pom.xml | 1 + project/pom.xml | 5 - 8 files changed, 168 insertions(+), 309 deletions(-) delete mode 100644 core/src/main/java/org/jclouds/crypto/pem/PKCS1EncodedPrivateKeySpec.java delete mode 100644 core/src/main/java/org/jclouds/crypto/pem/PKCS1EncodedPublicKeySpec.java diff --git a/core/pom.xml b/core/pom.xml index 307c1f2a2b..89a0dc3750 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -48,11 +48,6 @@ - - - org.bouncycastle - bcprov-jdk15on - javax.ws.rs jsr311-api diff --git a/core/src/main/java/org/jclouds/crypto/Pems.java b/core/src/main/java/org/jclouds/crypto/Pems.java index 607b03c7bf..9674867541 100644 --- a/core/src/main/java/org/jclouds/crypto/Pems.java +++ b/core/src/main/java/org/jclouds/crypto/Pems.java @@ -19,11 +19,21 @@ package org.jclouds.crypto; import static com.google.common.base.Charsets.US_ASCII; +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.Preconditions.checkState; +import static com.google.common.base.Splitter.fixedLength; import static com.google.common.base.Throwables.propagate; +import static com.google.common.base.Throwables.propagateIfInstanceOf; +import static com.google.common.io.BaseEncoding.base64; +import static com.google.common.io.ByteStreams.readBytes; import static com.google.common.io.Closeables.closeQuietly; +import static org.jclouds.crypto.ASN1Codec.decodeRSAPrivateKey; +import static org.jclouds.crypto.ASN1Codec.decodeRSAPublicKey; +import static org.jclouds.crypto.ASN1Codec.encode; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -43,20 +53,14 @@ import java.security.spec.RSAPrivateKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Map; -import org.bouncycastle.asn1.ASN1OutputStream; -import org.bouncycastle.asn1.pkcs.RSAPrivateKey; -import org.bouncycastle.util.io.pem.PemObject; -import org.bouncycastle.util.io.pem.PemReader; -import org.jclouds.crypto.Pems.PemProcessor.ResultParser; -import org.jclouds.crypto.pem.PKCS1EncodedPrivateKeySpec; -import org.jclouds.crypto.pem.PKCS1EncodedPublicKeySpec; import org.jclouds.io.InputSuppliers; import org.jclouds.javax.annotation.Nullable; import com.google.common.annotations.Beta; -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; +import com.google.common.base.Function; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; +import com.google.common.io.ByteProcessor; import com.google.common.io.InputSupplier; /** @@ -72,7 +76,7 @@ public class Pems { public static final String PUBLIC_X509_MARKER = "-----BEGIN PUBLIC KEY-----"; public static final String PUBLIC_PKCS1_MARKER = "-----BEGIN RSA PUBLIC KEY-----"; - public static class PemProcessor implements com.google.common.io.ByteProcessor { + public static class PemProcessor implements ByteProcessor { public interface ResultParser { T parseResult(byte[] bytes) throws IOException; } @@ -92,28 +96,94 @@ public class Pems { @Override public T getResult() { - PemReader reader = new PemReader(new StringReader(new String(out.toByteArray(), US_ASCII))); + Pem pem = PemReader.INSTANCE.apply(new String(out.toByteArray(), US_ASCII)); + String beginMarker = "-----BEGIN " + pem.type + "-----"; + checkState(parsers.containsKey(beginMarker), "Invalid PEM: no parsers for marker %s in %s", beginMarker, + parsers.keySet()); try { - PemObject pem = reader.readPemObject(); - byte[] bytes = pem.getContent(); - - // Bouncycastle removes the BEGIN and the markers when reading the PEM object - String beginMarker = "-----BEGIN " + pem.getType() + "-----"; - - checkState(parsers.containsKey(beginMarker), "Invalid PEM file: no parsers for marker %s in %s", - beginMarker, parsers.keySet()); - return parsers.get(beginMarker).parseResult(bytes); + return parsers.get(beginMarker).parseResult(pem.content); } catch (IOException e) { - throw propagate(e); - } finally { - closeQuietly(reader); + throw new IllegalStateException("Invalid PEM : " + pem, e); } } } /** - * Returns the object of generic type {@code T} that is pem encoded in the - * supplier. + * Parsed PEM format + * + *
+    *  -----BEGIN RSA PRIVATE KEY-----
+    *  Proc-Type: 4,ENCRYPTED
+    *  DEK-Info: DES-EDE3-CBC,3F17F5316E2BAC89
+    * 
+    *  ...base64 encoded data...
+    *  -----END RSA PRIVATE KEY-----
+    * 
+    * 
+ * + */ + private static enum PemReader implements Function { + INSTANCE; + private static final String BEGIN = "-----BEGIN "; + private static final String END = "-----END "; + + @Override + public Pem apply(CharSequence chars) { + checkNotNull(chars, "chars"); + BufferedReader reader = null; + try { + reader = new BufferedReader(new StringReader(chars.toString())); + Optional begin = skipUntilBegin(reader); + checkArgument(begin.isPresent(), "chars %s doesn't contain % line", chars, BEGIN); + String line = begin.get().substring(BEGIN.length()); + String type = line.substring(0, line.indexOf('-')); + StringBuilder encoded = new StringBuilder(); + + boolean reachedEnd = false; + while ((line = reader.readLine()) != null) { + if (line.indexOf(':') >= 0) { // skip headers + continue; + } + if (line.indexOf(END + type) != -1) { + reachedEnd = true; + break; + } + encoded.append(line.trim()); + } + + checkArgument(reachedEnd, "chars %s doesn't contain % line", chars, END); + return new Pem(type, base64().decode(encoded.toString())); + } catch (IOException e) { + throw new IllegalStateException(String.format("io exception reading %s", chars), e); + } finally { + closeQuietly(reader); + } + + } + + private static Optional skipUntilBegin(BufferedReader reader) throws IOException { + String line = reader.readLine(); + while (line != null && !line.startsWith(BEGIN)) { + line = reader.readLine(); + } + return Optional.fromNullable(line); + } + } + + private static final class Pem { + + private final String type; + private final byte[] content; + + private Pem(String type, byte[] content) { + this.type = checkNotNull(type, "type"); + this.content = checkNotNull(content, "content"); + } + + } + + /** + * Returns the object of generic type {@code T} that is pem encoded in the supplier. * * @param supplier * the input stream factory @@ -121,19 +191,17 @@ public class Pems { * header that begins the PEM block * @param processor * how to parser the object from a byte array - * @return the object of generic type {@code T} which was PEM encoded in the - * stream + * @return the object of generic type {@code T} which was PEM encoded in the stream * @throws IOException * if an I/O error occurs */ public static T fromPem(InputSupplier supplier, PemProcessor processor) throws IOException { try { - return com.google.common.io.ByteStreams.readBytes(supplier, processor); + return readBytes(supplier, processor); } catch (RuntimeException e) { - if (e.getCause() != null && e.getCause() instanceof IOException) { - throw (IOException) e.getCause(); - } + propagateIfInstanceOf(e.getCause(), IOException.class); + propagateIfInstanceOf(e, IOException.class); throw e; } } @@ -151,14 +219,9 @@ public class Pems { public static KeySpec privateKeySpec(InputSupplier supplier) throws IOException { return fromPem( supplier, - new PemProcessor(ImmutableMap.> of(PRIVATE_PKCS1_MARKER, - new ResultParser() { - @Override - public KeySpec parseResult(byte[] bytes) throws IOException { - return new PKCS1EncodedPrivateKeySpec(bytes).getKeySpec(); - } - - }, PRIVATE_PKCS8_MARKER, new ResultParser() { + new PemProcessor(ImmutableMap.> of( + PRIVATE_PKCS1_MARKER, DecodeRSAPrivateCrtKeySpec.INSTANCE, PRIVATE_PKCS8_MARKER, + new PemProcessor.ResultParser() { @Override public KeySpec parseResult(byte[] bytes) throws IOException { return new PKCS8EncodedKeySpec(bytes); @@ -168,8 +231,23 @@ public class Pems { } /** - * Executes {@link Pems#privateKeySpec(InputSupplier)} on the string which - * contains an encoded private key in PEM format. + * Decode PKCS#1 encoded private key into RSAPrivateCrtKeySpec. + * + * @param keyBytes + * Encoded PKCS#1 rsa key. + */ + private static enum DecodeRSAPrivateCrtKeySpec implements PemProcessor.ResultParser { + INSTANCE; + + @Override + public KeySpec parseResult(byte[] bytes) throws IOException { + return decodeRSAPrivateKey(bytes); + } + } + + /** + * Executes {@link Pems#privateKeySpec(InputSupplier)} on the string which contains an encoded private key in PEM + * format. * * @param pem * private key in pem encoded format. @@ -196,15 +274,8 @@ public class Pems { public static KeySpec publicKeySpec(InputSupplier supplier) throws IOException { return fromPem( supplier, - new PemProcessor(ImmutableMap.> of(PUBLIC_PKCS1_MARKER, - new ResultParser() { - - @Override - public KeySpec parseResult(byte[] bytes) throws IOException { - return new PKCS1EncodedPublicKeySpec(bytes).getKeySpec(); - } - - }, PUBLIC_X509_MARKER, new ResultParser() { + new PemProcessor(ImmutableMap.> of(PUBLIC_PKCS1_MARKER, + DecodeRSAPublicKeySpec.INSTANCE, PUBLIC_X509_MARKER, new PemProcessor.ResultParser() { @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 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 diff --git a/project/pom.xml b/project/pom.xml index 0b15aaf3e3..f1bab7a887 100644 --- a/project/pom.xml +++ b/project/pom.xml @@ -204,11 +204,6 @@ - - org.bouncycastle - bcprov-jdk15on - 1.47 - com.jcraft jsch